传送门:http://codevs.cn/problem/5624/
算法一(送分算法):
最朴素的算法应该就是四重循环暴力枚举每一个
xa,xb,xc,xd
当然只能通过较少的点
于是
O(n4)
算法二(骗分算法):
由算法一改变一下便可以省下一重循环
暴力出
xa,xb,xc,然后计算出xd
于是
O(n3)
当然还可以加一些常数上的优化 比如确定
xa,xb后,xc
其实范围已经缩小了
算法三(似乎可以AC):
可以算是一个折半枚举吧
用 ans[x][y] 记录 数x(注意不是第x个)在位置y上出现的次数
那么枚举差值 i ,
再枚举
xa
则 :
xb=xa+i∗2;
xc>xb+i∗6=xa+i∗8;
xd=xc+i;
换句话说
xb
已确定下来
然后再来研究一下
xc,xd
当
xc
确定下来后,
xd
也确定下来
并且随着
xa
的增大
xc
的范围单调递减(反过来就是随着
xa
的增大,
xc
的范围单调递增)
于是就可以利用这一性质求出
sum=∑(f[xc]∗f[xd])
然后就能累加到
ans[xa][1]和ans[xb][2]
上
同理累加
ans[xc][3]和ans[xd][4]
详见代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,sum,A,B,C,D,a[40005],f[20005],ans[20005][5];
int main(){
cin>>n>>m;
for (int i=1;i<=m;i++){
cin>>a[i];
f[a[i]]++;
}
for (int i=1;i<=2000;i++){
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+=f[C]*f[D];
ans[A][1]+=f[B]*sum;
ans[B][2]+=f[A]*sum;
}
sum=0;
for (C=2+8*i;C<=n;C++){
A=C-8*i-1; B=C-6*i-1; D=C+i;
sum+=f[A]*f[B];
ans[C][3]+=f[D]*sum;
ans[D][4]+=f[C]*sum;
}
}
for (int i=1;i<=m;i++)
cout<<ans[a[i]][1]<<' '<<ans[a[i]][2]<<' '<<ans[a[i]][3]<<' '<<ans[a[i]][4]<<'\n';
return 0;
}