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

By WZY

优质内容筛选与推荐>>
1、php进程的SIGBUS故障
2、笔记整理——C语言-http
3、LCS: Longest Common Subsequence / String 总结
4、利用StateListDrawable给button动态设置背景
5、用php描述顺序查找


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号