给出一个序列(a),对于每一个(a_k),输出有多少个有序二元组(a_i imes a_jequiv (mod a_k))
这看一眼就像是fft问题,fft一般可以统计加法的情况,但这里是乘法。
原根可以把乘法变成加法,仔细一看模,是([2,200000])的质数,根据原根存在定理,奇质数肯定存在原根,2也存在原根。
求质数的原根,时间复杂度是(O(plogp))。
然后利用原根打一个指标表,是(O(n))
然后再利用原根把所有的非零(a_i)转换为指标,把序列(a)的各项的指标作为系数累积。
最后把这个多项式进行自乘。
就能得到一个指标多项式。
原根可以把乘法变成加法,然后利用fft的性质求解
#include <bits/stdc++.h>
#define ll long long
using namespace std;
template<typename T = long long> inline T read() {
T s = 0, f = 1; char ch = getchar();
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) {s = (s << 3) + (s << 1) + ch - 48; ch = getchar();}
return s * f;
}
const int N = 5e5 + 5;
namespace PrimitiveRoot {
vector<int> PrimeFactor(int n) {//分解质因子
vector<int> fac;
for(int i = 2; i * i <= n; ++i) {
if(n % i == 0){
fac.push_back(i);
while(n % i == 0) n /= i;
}
}
if(n > 1) fac.push_back(n);
return fac;
}
int gcd(int a, int b){
return b == 0 ? a : gcd(b, a % b);
}
ll qpow(ll a, ll b, ll p){
ll ans = 1; a %= p;
while(b){
if(b & 1) ans = ans * a % p;
a = a * a % p;
b >>= 1;
}
return ans;
}
int phi(int n){
return n - 1;
int ans = n;
for(int i = 2; i * i <= n; i++){
if(n % i == 0){
ans -= ans/i;
while(n % i == 0) n /= i;
}
}
if(n > 1) ans -= ans / n;
return ans;
}
bool checkroot(int x) {
if(x == 2 ||x == 4) return true;
if(x % 4 == 0) return false;
if(x % 2 == 0) x /= 2;
for(int i = 2; i * i <= x; ++i){
if(x % i == 0){
while(x % i == 0) x /= i;
return x == 1;
}
}
return true;
}
int PrimitiveRoot(int p) { // 求p最小的原根
int nowphi = phi(p);
std::vector<int> fac = PrimeFactor(nowphi);
for(int g = 2; g < p; g++) {
bool f = 1;
for(int j = 0; j < fac.size(); j++)
if(qpow(g, nowphi / fac[j], p) == 1) {f = 0; break; }
if(f) return g;
}
return -1; // 没有原根
}
void solve(int x){ //得到全部的原根
if(!checkroot(x)) {
printf("0
");; return;
}
int nowphi = phi(x);
int g = PrimitiveRoot(x);
vector<int> ans; ans.push_back(g); // 所有原根
for(int i = 2; i < nowphi; ++i){
if(gcd(i, nowphi) == 1) ans.push_back(qpow(g, i, x));
}
}
};
struct Complex{
double x, y;
Complex(double x = 0, double y = 0):x(x),y(y){};
inline Complex operator + (const Complex b) const {
return Complex(x + b.x,y + b.y);
}
inline Complex operator - (const Complex b) const {
return Complex(x - b.x,y - b.y);
}
inline Complex operator * (const Complex b) const {
return Complex(x * b.x - y * b.y, x * b.y + y * b.x);
}
};
namespace FFT{
const double Pi = acos(-1);
const int N = 5e5 + 5; // 刚好比n大的2的k次方再乘2
Complex F[N], G[N];
int r[N], n, m;
void FFT(Complex *a, int n, int inv){
for(int i = 0; i < n; i++)
if(r[i] > i) swap(a[r[i]], a[i]);
for(int mid = 2; mid <= n; mid <<= 1){
Complex x(cos(2 * Pi / mid), inv * sin(2 * Pi / mid));
for(int i = 0; i < n; i += mid){
Complex w(1,0);
for(int j = i; j < i + (mid >> 1); j++, w = w * x){
Complex t1 = a[j],t2 = a[j + (mid >> 1)] * w;
a[j] = t1 + t2; a[j + (mid >> 1)] = t1 - t2;
}
}
}
}
void mul(ll *a, ll *b, ll *c, int nn, int mm, int &k) {
n = nn, m = mm;
for(mm += nn, nn = 1; nn <= mm; nn *= 2);
for(int i = 0; i <= nn; i++) F[i].x = F[i].y = G[i].x = G[i].y = 0;
for(int i = 0; i <= n; i++) F[i].x = a[i];
for(int i = 0; i <= m; i++) G[i].x = b[i];
int l = 0;
for(m += n, n = 1; n <= m; n *= 2, l++);
for(int i = 0; i < n; i++)
r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
FFT(F, n, 1); FFT(G, n, 1);
for(int i = 0; i < n; i++) F[i] = F[i] * G[i];
FFT(F, n, -1); k = m;
for(int i = 0; i <= m; i++) {
c[i] = (ll)(F[i].x / n + 0.5);
}
}
};
int I[N];
void I_table(int g, int p){
int base = 1;
for(int i = 1; i < p - 1; i++) {
base = base * g % p;
I[base] = i;
}
}
int a[N], b[N];
ll xishu[N], ans[N], c[N];
int main() {
int n = read(), p = read();
I_table(PrimitiveRoot::PrimitiveRoot(p), p);
for(int i = 1; i <= n; i++) a[i] = read();
int tot = 0;
for(int i = 1; i <= n; i++) {
if(a[i] % p == 0) tot++;
else xishu[I[a[i] % p]]++;
}
int m;
FFT::mul(xishu, xishu, c, p - 1, p - 1, m);
for(int i = 0; i < p * 2; i++) ans[i % (p - 1)] += c[i];
for(int i = 1; i <= n; i++) {
if(a[i] >= p) printf("0
");
else if(a[i] == 0) printf("%lld
", 1ll * tot * (n - tot) * 2 + 1ll * tot * tot);
else printf("%lld
", ans[I[a[i]]]);
}
return 0;
}