【NOIP2016普及组】复赛——魔法阵

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


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

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


此题正确思路:

先看看要满足的条件: Xab)/3

所以我们能得到一个图:

【NOIP2016普及组】复赛——魔法阵_第1张图片

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

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
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\n",ans[h[i]][1],ans[h[i]][2],ans[h[i]][3],ans[h[i]][4]);//输出
    return 0;
}

                                                                                                                                                                               By WZY

转载于:https://www.cnblogs.com/LinqiongTaoist/p/7203745.html

你可能感兴趣的:(【NOIP2016普及组】复赛——魔法阵)