分析
首先显然与物品数量无关,用一个桶记录每个数的出现次数即可
题目的数据随机告诉我们(O(n^2))的算法可能能够卡过去,但显然要找一些更优的算法
然后研究一下性质,发现(x_b-x_a)出现了两次,那存不存在一个量可以尽量表达(x_a,x_b,x_c,x_d)
考虑枚举(t=x_d-x_c),因为它是(x_b-x_a)的(frac{1}{2})倍,所需要枚举的范围可能会更小
那么(x_b-x_a=2t,x_c-x_b>6t),那我枚举的(t)只需要在((n-1)/9)内就行了
那肯定还要枚举一个数,由于(x_c-x_b)不能完全确定,不妨分成两种情况:
- 当枚举(x_a)时,求(x_a)和(x_b)的方案数,那(x_c)和(x_d)其实可以用后缀和表示
- 当枚举(x_d)时,求(x_c)和(x_d)的方案数,那(x_a)和(x_b)其实可以用前缀和表示
时间复杂度(O(frac{1}{9}n^2)),实际上常数非常小
代码
#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=40011;
int m,n,a[N],c[N],ans[4][N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
signed main(){
m=iut(); n=iut();
for (rr int i=1;i<=n;++i) ++c[a[i]=iut()];
for (rr int i=1;i*9<m;++i){
for (rr int D=9*i+2,s=0;D<=m;++D){
rr int C=D-i,B=C-6*i-1,A=B-2*i;
s+=c[A]*c[B],ans[2][C]+=c[D]*s,ans[3][D]+=c[C]*s;
}
for (rr int A=m-9*i-1,s=0;A;--A){
rr int B=A+2*i,C=B+6*i+1,D=C+i;
s+=c[C]*c[D],ans[0][A]+=c[B]*s,ans[1][B]+=c[A]*s;
}
}
for (rr int i=1;i<=n;++i)
for (rr int j=0;j<4;++j)
print(ans[j][a[i]]),putchar(j==3?10:32);
return 0;
}