【搜索】魔法阵

传送门:CodeVS5624


算法一(送分算法):

最朴素的算法应该就是四重循环暴力枚举每一个 $x_a,x_b,x_c,x_d$ 当然只能通过较少的点 于是$O(n^4)$


算法二(骗分算法):

由算法一改变一下便可以省下一重循环 暴力出 $x_a,x_b,x_c ,然后计算出 x_d$ 于是$O(n^3)$ 当然还可以加一些常数上的优化 比如确定 $x_a,x_b 后,x_c$ 其实范围已经缩小了


算法三(似乎可以AC):

可以算是一个折半枚举吧 用 $ans^{xy}$ 记录 数x(注意不是第x个)在位置y上出现的次数 那么枚举差值 i , 再枚举 $x_a$ 则 : $x_b=x_a+i*2;$ $x_c>x_b+i*6=x_a+i*8;$ $x_d=x_c+i;$ 换句话说 $x_b$ 已确定下来 然后再来研究一下 $x_c,x_d$$x_c$ 确定下来后,$x_d$ 也确定下来 并且随着 $x_a$ 的增大 $x_c$ 的范围单调递减(反过来就是随着 $x_a$ 的增大,$x_c$ 的范围单调递增) 于是就可以利用这一性质求出 $sum=\sum(f[x_c]*f[x_d])$ 然后就能累加到 $ans[x_a][1] 和 ans[x_b][2]$ 上 同理累加 $ans[x_c][3] 和 ans[x_d][4]$


详见代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#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;
}