NOIP2016T4 魔法阵
博客阅读效果更佳qwq
很好的一道数学推导题
45分做法
所以②可化为
将④代入③
移项一下,就变成
由图可得
所以我们可以尝试着枚举t,用t来表示各个魔法值的值
由上易得t的范围为
在代码中为了避免除法写成
再枚举D,因为我们已经枚举出了t,所以C的值是可以直接算出来的
又因为使
那么如果A和B更小怎么办?
观察到在其他条件不变的情况下,只要
然后又由乘法原理可得,当前魔法值作为
所以我们利用前缀和优化
C的情况可以顺便在算D的时候算出来
那么还有一个问题是,我们枚举的D的范围是多少?
因为要统计前缀和,所以一定是要顺推下去的,由上面那张图我们可以知道,D的最大值为n,最小值则为当k=1且A=1的时候,所以D的最小值为
同理可以枚举A
但是这个的情况又和枚举D的情况有一点不同
在其他条件不变的情况下,只要
因为需要统计后缀和,所以需要逆推
枚举的范围:A的最大值为
所以就可以算出每个魔法值作为
#include <cstdio>
#include <algorithm>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
#define N 50010
int n,m;
int a[N],b[N],c[N],d[N];
int x[N],vis[N];
int main(){
n=read();m=read();
for(int i=1;i<=m;i++)
x[i]=read(),vis[x[i]]++;
for(int t=1;t*9<n;t++){
int sum=0;
for(int D=9*t+2;D<=n;D++){
int A=D-9*t-1;
int B=A+2*t;
int C=D-t;
sum+=vis[A]*vis[B];
c[C]+=vis[D]*sum;
d[D]+=vis[C]*sum;
}
sum=0;
for(int A=n-9*t-1;A;A--){
int B=A+2*t;
int C=B+6*t+1;
int D=A+9*t+1;
sum+=vis[C]*vis[D];
a[A]+=vis[B]*sum;
b[B]+=vis[A]*sum;
}
}
for(int i=1;i<=m;i++){
printf("%d %d %d %d\n",a[x[i]],b[x[i]],c[x[i]],d[x[i]]);
}
return 0;
}