zoukankan      html  css  js  c++  java
  • [NOIP2016]魔法阵

    题目传送门


     暴力貌似能拿55,不过我没写 

    读完题我们貌似可以推个式子:

    ∵b-a=2*(d-c)(这里我们用i来代替xi)

    ∴可以设d-c=i,则b-a=2*i

    又∵b-a<(c-b)/3

    ∴2i<(c-b)/3

    ∴6i<c-b

    同时∵不等式是<

    ∴6i+k=c-b (k>=1)

    于是我们可以得到下图:

     对于85分做法,我们很容易想到:

    我们可以利用三重循环:

    1. 枚举a的数值,范围:1->n
    2. 枚举i的数值,范围:1->(n-a-1)/9
    3. 枚举k的数值,范围:1->n-a-9*i

    但是有一点需要注意,每一次发现合法魔法阵时

    由于我们枚举的是魔法数值,于是若有相同魔法数值的两个魔法物品无法判断

    所以我们在输入时就需要存一下每个魔法数值的魔法物品有多少个

    然后每次加的时候用乘法原理处理一下就可以了

    code-85:

    #include<bits/stdc++.h>
    using namespace std;
    const int M=40010;
    const int N=15010;
    int n,m,b,c,d;
    int x[M],ans[10][M],p[N];
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&x[i]);
            p[x[i]]++;
        }
        for(int a=1;a<=n;a++)
        {
            if(p[a]==0) continue;
            for(int i=1;i<=(n-a-1)/9;i++)
            {
                b=a+2*i;
                if(p[b]==0) continue;
                for(int k=1;k<=n-a-9*i;k++)
                {
                    c=b+6*i+k;
                    if(p[c]==0) continue;
                    d=c+i;
                    if(p[d]==0) continue;
    //                cout<<a<<' '<<b<<' '<<c<<' '<<d<<endl;
                    ans[1][a]=ans[1][a]+p[b]*p[c]*p[d];
                    ans[2][b]=ans[2][b]+p[a]*p[c]*p[d];
                    ans[3][c]=ans[3][c]+p[a]*p[b]*p[d];
                    ans[4][d]=ans[4][d]+p[a]*p[b]*p[c];
                }
            }
        }
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=4;j++)
                printf("%d ",ans[j][x[i]]);
            puts("");
        }
        return 0;
    }
    Code-85 

    然后我们发现这个算法的时间复杂度是O((n^3)/9)于是还是会爆

    然后,在考场上就没有然后了……


     然后看了题解之后,就非常……

    思路还是之前那样,求出了所有式子,因为循环三层会爆,所以我们就要尝试简化

    由于k不确定,所以我们就不管它(迷惑

    然后第一层循环i,第二层先循环d

    由于c和d只差i,所以我们现在能知道c和d,再设k=1,便可以求出对应的a和b

    如果我们将d右移之后得到了d'和c',同时又可以得到k=1的a'和b'

    但是我们发现d',c',a,b同样可以组成合法的魔法阵,所以考虑利用类似前缀和的方法

    定义sum为从d=9*i+2开始的所对应的的a,b的魔法阵数量和

    再计算完c,d之后用同样的方法计算a,b即可

    code-100:

    #include<bits/stdc++.h>
    using namespace std;
    const int M=40010;
    const int N=15010;
    int n,m,a,b,c,d;
    int x[M],ans[10][M],p[N];
    inline int read()
    {
        int f=1,x=0;char ch=getchar();
        while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0' && ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
        return x*f;
    }
    int main()
    {
        n=read();m=read();
        for(int i=1;i<=m;i++)
        {
            x[i]=read();
            p[x[i]]++;
        }
        for(int i=1;i*9<n;i++)
        {
            int sum=0;
            for(d=i*9+2;d<=n;d++)
            {
                a=d-9*i-1;
                b=d-7*i-1;
                c=d-i;
                sum+=p[a]*p[b];
                ans[3][c]+=sum*p[d];
                ans[4][d]+=sum*p[c];
            }
            sum=0;
            for(a=n-9*i-1;a>=1;a--)
            {
                b=a+2*i;
                c=a+8*i+1;
                d=a+9*i+1;
                sum+=p[c]*p[d];
                ans[1][a]+=sum*p[b];
                ans[2][b]+=sum*p[a];
            }
        }
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=4;j++)
                printf("%d ",ans[j][x[i]]);
            puts("");
        }
        return 0;
    }
    Code-100
  • 相关阅读:
    Linux 安装中文man手册
    centos6.9使用NTFS-3G挂载ntfs文件系统
    Linux基础知识之挂载详解(mount,umount及开机自动挂载)
    技术点总结
    SQL 分组后获取其中一个字段最大值的整条记录 【转载】
    线程池之ThreadPool类与辅助线程
    Task.Run使用默认线程池
    VS生成事件
    线程池之ThreadPoolExecutor使用
    Sql笔记
  • 原文地址:https://www.cnblogs.com/juruo-hxy/p/13694806.html
Copyright © 2011-2022 走看看