洛谷P2119 [NOIP2016 普及组] 魔法阵

传送门
初步想法,枚举四个物品,明显爆炸
之后想办法优化
看到n1e4的取值范围,我们很容易就能get到这个题应该用桶的方式来解决
具体怎么搞呢?
我们来观察一下他给的等式以及不等式
最小的单位应该是D与C之间的差值
我们设这个值为t,可以通过枚举t来进行计算。
首先,我们可以知道,A的最小值是1,D的最大值是N
A与B之间的差距是2t
B和C之间的差距大于6t,C和D之间的差距为t
我们不妨在第一层循环枚举t,之后怎么搞呢?
我们假设已经知道一个D的值,我们现在要统计他作为D出现了几次,怎么统计呢?
首先,D确定,枚举t,那么C也确定,而A和B会有一些二元组,每组的AB差为2t,并且最大的A为D-9t-1。
我们只需要把所有符合答案的sumasumbsumc相乘就是D的答案,注意,这个suma✖sumb是一个二元组的值,我们枚举D应该把前面所有符合条件的都加到一起。
那我们怎么搞呢?
你再枚举A-B是肯定会T飞的,不如用前缀和的思想,我们对于每个T,从D的min开始枚举,那么A也是从MIN开始的,然后用一个sum记录当前t的suma*sumb前缀和,于是C&&D的答案就可以求出来
同理,对于A和B,我们也可以用类似的思想来求出来

一道挺有意思的小数学题
希望以后能去打比赛

#include <bits/stdc++.h>
using namespace std;
const int M=40005;
int n,m;
int num[15005];
int a_sum[150005],b_sum[15005],c_sum[15005],d_sum[15005];
struct Node{
    int id,val;
}zhn[M];
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline bool cmp(Node a,Node b){
    if(a.val!=b.val) return a.val<b.val;
    return a.id<b.id;
}
int main(){
    n=read();m=read();
    int maxx=0;
    for(int i=1;i<=m;i++){
        zhn[i].id=i;
        zhn[i].val=read();
        num[zhn[i].val]++;
    }
    for(int t=1;t<=n/9;t++){
        int sum=0;
        for(int D=9*t+2;D<=n;D++){
            int C=D-t;
            int B_MAX=D-7*t-1;
            int A_MAX=D-9*t-1;
            sum+=num[B_MAX]*num[A_MAX];
            c_sum[C]+=sum*num[D];
            d_sum[D]+=sum*num[C];
        }
        sum=0;
        for(int A=n-9*t-1;A>=1;A--){
            int B=A+2*t;
            int C=B+6*t+1;
            int D=C+t;
            sum+=num[C]*num[D];
            a_sum[A]+=sum*num[B];
            b_sum[B]+=sum*num[A];
        }
    }
    for(int i=1;i<=m;i++) printf("%d %d %d %d\n",a_sum[zhn[i].val],b_sum[zhn[i].val],c_sum[zhn[i].val],d_sum[zhn[i].val]);
    return 0;
}

上一篇:安装cuda加速的OpenCV


下一篇:P2822 [NOIP2016 提高组] 组合数问题