传送门
初步想法,枚举四个物品,明显爆炸
之后想办法优化
看到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;
}