zoukankan      html  css  js  c++  java
  • 【NOIP2016普及组】复赛——魔法阵

    题目来这里:跟我飞飞飞(不要问我为什么,自己看前3篇题解)


    还能怎么做,要么爆搜要么递归,要么超时要么栈溢出……

    其实这次复赛的题几乎没有什么算法,数据结构也就3题算用了队列,全部是考思维。


    此题正确思路:

    先看看要满足的条件: Xa<Xb<Xc<Xd,Xb-Xa=2(Xd-Xc),且Xb-Xa<(Xc-Xb)/3

    所以我们能得到一个图:


    相信这个不难理解,结合上面的条件变能够看懂(其实最重要的第一步就是先画好图)。

    i当然是正整数,所以当我们枚举时外层循环便是i,从多少到多少呢?

    题告诉我们,数据中的数均不超过n,所以我们就是枚举到n……吗?显然可以看出,图中一共是>9i的,所以只需要枚举到n/9便可以了。

    外层循环枚举i,那里面呢?也不需要abcd挨个枚举。

    我们只需要先枚举最后的d,由d可以知道c和d的数量,d的数量便是它之前的a,b,c的数量的乘积(当然不可能是加起来),c也一样。

    然后枚举最前面的a,由a又可以知道b,a的数量便是它之前的b,c,d的乘积,b一样。

    可能有一点动态规划的思想。

    就这些了,我知道你很懵逼,看看代码吧:

    #include<cstdio>
    int h[40005],w[15005];//h为魔法值,w为每种魔法值出现的次数
    int ans[15005][5];//答案不解释
    int n,m;
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&h[i]);
            w[h[i]]++;//此物品次数++
        }
        for(int i=1;i<=n/9;i++)
        {
            int a=1,d,tmp=0;//先默认a为1
            for(d=i*9+2;d<=n;d++)//枚举d(a为整数,c-b要>6i,所以要加2)
            {
                tmp+=w[a+2*i]*w[a]; a++;//ab次数的乘积(本来最后可以写w[a++]的,但不知为什么有警告(不影响))
                ans[d][4]+=tmp*w[d-i];//d的次数为ab次数乘c
                ans[d-i][3]+=tmp*w[d];//c的次数为ab次数乘d
            }
            tmp=0,d=n;
            for(a=n-9*i-1;a>=1;a--)//不能正着枚举a,因为这样tmp的累加就有问题了
            {
                tmp+=w[d-i]*w[d]; d--;
                ans[a][1]+=tmp*w[a+2*i];
                ans[a+2*i][2]+=tmp*w[a];//这些都和上面大同小异
            }
        }
        for(int i=1;i<=m;i++)
            printf("%d %d %d %d
    ",ans[h[i]][1],ans[h[i]][2],ans[h[i]][3],ans[h[i]][4]);//输出
        return 0;
    }

                                                                                                                                                                                   By WZY

  • 相关阅读:
    星空雅梦
    星空雅梦
    星空雅梦
    星空雅梦
    星空雅梦
    星空雅梦
    星空雅梦
    星空雅梦
    lambda表达式
    VIM--保存和退出等命令
  • 原文地址:https://www.cnblogs.com/LinqiongTaoist/p/7203745.html
Copyright © 2011-2022 走看看