steins;Gate - 牛客
题意
有\(n\)个数\(a_1,a_2,\dots,a_n\)。对于每一个\(a_k\),求有多少个有序二元组\((i,j)\)满足\((a_i * a_j) mod(P) = a_k\),其中\(P\)为一给定质数。
\(1 \le N \le 200000,2 \le P\le 200000,0 \le a_i\le2100000000\)
符号
g :\(P\)的原根
题解
因为\(a_i mod P = g^t,(0 < t < P )\),实际上转换成\([ 0, P - 1)\)要方便很多。所以\((a_i * a_j) mod(P) = ((a_i mod P) * (a_j mod P) mod(P)) = g^{t_1+t_2} mod (P) = a_k\)。将乘法变成了加法,\(FFT\)就能用上了,和\(hdu4609\)的处理方法是一样的,kuangbin聚聚写的很清楚,也算是一个套路了。为什么要把模\(P\)等于0的数扣出来,因为这样的数是不能用原根表示的。
代码
const int N = 600010;
struct Complex {
double r,i;
Complex(double real=0.0,double image=0.0) {
r=real;
i=image;
}
Complex operator +(const Complex o){return Complex(r+o.r,i+o.i);}
Complex operator -(const Complex o){return Complex(r-o.r,i-o.i);}
Complex operator *(const Complex o){return Complex(r*o.r-i*o.i,r*o.i+i*o.r);}
} b[N];
int rev(int id, int len) {
int pos = 0;
for (int i = 0; (1 << i) < len; ++i) {
pos <<= 1;
if (id & (1 << i)) pos |= 1;
}
return pos;
}
Complex A[N];
void FFT(Complex *a, int len, int DFT) {
rep(i, 0, len) A[rev(i, len)] = a[i];
for (int s = 1; (1 << s) <= len; ++s) {
int m = (1 << s);
Complex wm = Complex(cos(DFT * 2 * PI / m), sin(DFT * 2 * PI / m));
for (int i = 0; i < len; i += m) {
Complex w = Complex(1, 0);
for (int j = 0; j < (m >> 1); ++j) {
Complex t = A[i + j];
Complex u = w * A[i + j + (m >> 1)];
A[i + j] = t + u;
A[i + j + (m >> 1)] = t - u;
w = w * wm;
}
}
}
if (DFT == -1) rep(i, 0, len) A[i].r /= len, A[i].i /= len;
rep(i, 0, len) a[i] = A[i];
}
int n, g, P;
int a[N], id[N];
LL ans[N];
bool check(int g) {
LL t = 1;
rep(i, 1, P - 1) {
t = t * g % P;
if (t == 1) return 0;
}
return 1;
}
int qpow(int x, int y) {
int res = 1;
for (; y; x = 1ll * x * x % P, y >>= 1) if (y & 1) res = 1ll * res * x % P;
return res;
}
int main()
{
sc(n), sc(P);
for (int i = 2; ; ++i) if (check(i)) {
g = i;
break;
}
LL t = 1;
rep(i, 1, P) {
t = t * g % P;
id[t] = i;
}
t = 0;
Rep(i, 1, n) {
sc(a[i]);
if (a[i] % P == 0) t++;
else b[id[a[i] % P]].r++;
}
int len = (1 << 19);
FFT(b, len, 1);
rep(i, 0, len) b[i] = b[i] * b[i];
FFT(b, len, -1);
// 当P = 2时,i = 0也有贡献
rep(i, 0, len) ans[qpow(g, i)] += (LL)(b[i].r + 0.5);
Rep(i, 1, n) {
if (a[i] >= P) printf("0\n");
else if (a[i] == 0) printf("%lld\n", t * t + 2 * t * (n - t));
else printf("%lld\n", ans[a[i]]);
}
return 0;
}