[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分做法,我们很容易想到:
我们可以利用三重循环:
- 枚举a的数值,范围:1->n
- 枚举i的数值,范围:1->(n-a-1)/9
- 枚举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; }
然后我们发现这个算法的时间复杂度是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; }