更好的阅读体验
题目传送门
-
给定 a1∼an,求当 x∈[1,p) 时满足以下条件的有序三元组 (i,j,k) 的数量:
-
i=j,j=k,k=i.
-
(ai⋅aj+ak)modp=x.
-
1≤n,p≤5000,0≤n≤109.
Solution
分别求 x=1∼p−1 时的答案 ansx.对于枚举的每一个 x,枚举 k=1∼n,这样可以得到 ai⋅ajmodp=(x−ak)modp.
考虑预处理 vw(w∈[1,p)) 表示满足 ai⋅ajmodp=w 的有序对 (i,j)(i=j) 的个数. 这个可以枚举两个数,然后将它们乘积的余数对应的 v 值 +1. 这样对于枚举的 k,直接将 ansx 加上 v(x−ak)modp 即可.
不过 v(x−ak)modp 可能计算了 ak 去乘上某个数,因此还要预处理 ui,j(i∈[1,n],j∈[1,p)),表示满足 ai⋅atmodp=j(t=i,t∈[1,n]) 的 t 的个数. 这个可以枚举 i,t 两个数,然后然后将它们乘积的余数对应的 ui 值 +1.
最后再把 ansx 减去 2⋅uk,x 即可. 注意是 2 倍,因为 v 的值是有序对个数,当 i=k,j=k 时都要减去 uk,x.
时间复杂度为 O(n2+np),空间复杂度为 O(np+n+p),可以接受.
Code
点击查看代码
#include<bits/stdc++.h>
#define int long long//相乘会见祖宗.
#define N 5001
using namespace std;
int u[N][N],v[N],p,n,a[N];
signed main(){
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
cin>>n>>p;
for(int i=1;i<=n;++i){
cin>>a[i];
}
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
if(i^j){
++v[a[i]*a[j]%p];
++u[i][a[i]*a[j]%p];
}
}
}
for(int i=0,k;i<p;++i){
k=0;
for(int j=1,q;j<=n;++j){
q=(i-a[j]+p*1145141919810)%p;//注意负数取模.
k+=v[q]-u[j][q]*2;
}
cout<<k<<' ';
}
}
测评链接