牛客國慶集訓派對Day1 I Steins;Gate(FFT+原根)
阿新 • • 發佈:2018-12-13
思路:求出p的原根,那麼乘法就變成了加法,FFT跑一下,下標在稍微轉換一下就好了。
#include <cstdio> #include <cstdlib> #include <cstring> #include <bitset> #include <cmath> #include <cctype> #include <iostream> #include <algorithm> #include <string> #include <vector> #include <queue> #include <map> #include <set> #include <sstream> #include <iomanip> using namespace std; typedef long long ll; typedef unsigned long long ull; const ll inff = 0x3f3f3f3f3f3f3f3f; #define FOR(i,a,b) for(int i(a);i<=(b);++i) #define FOL(i,a,b) for(int i(a);i>=(b);--i) #define REW(a,b) memset(a,b,sizeof(a)) #define inf int(0x3f3f3f3f) #define si(a) scanf("%d",&a) #define sl(a) scanf("%I64d",&a) #define sd(a) scanf("%lf",&a) #define ss(a) scanf("%s",a) #define mod ll(998244353) #define pb push_back #define eps 1e-6 #define lc d<<1 #define rc d<<1|1 #define Pll pair<ll,ll> #define P pair<int,int> #define pi acos(-1) ll n,p,g,id[200008],a[200008],m,ans[500008]; bool as(ll x) { ll tmp=1; FOR(i,1,p-2) { tmp=tmp*x%p; if(tmp==1) return 0; } return 1; } struct CP{ double x,y; CP(){} CP(double a,double b):x(a),y(b){} CP operator+(const CP&r) const{return CP(x+r.x,y+r.y);} CP operator-(const CP&r) const{return CP(x-r.x,y-r.y);} CP operator*(const CP&r) const{return CP(x*r.x-y*r.y,x*r.y+y*r.x);} }b[500008],t; inline void Swap(CP&a,CP&b) {t=a;a=b;b=t;} inline void fft(CP*a,int f,int n) { int i,j,k; for(i=j=0;i<n;i++) { if(i>j) Swap(a[i],a[j]); for(k=n>>1;(j^=k)<k;k>>=1); } for(int i=1;i<n;i<<=1) { CP wn(cos(pi/i),f*sin(pi/i)); for(int j=0;j<n;j+=i<<1) { CP w(1,0); for(int k=0;k<i;k++,w=w*wn) { CP x=a[j+k],y=w*a[i+j+k]; a[j+k]=x+y;a[i+j+k]=x-y; } } } if(f==-1) FOR(i,0,n) a[i].x/=n; } int main() { cin.tie(0); cout.tie(0); cin>>n>>p; for(ll i=2;;i++) if(as(i)) {g=i;break;} ll tmp=1,qw=0,er; for(int i=1;i<p-1;i++) { tmp=tmp*g%p; id[tmp]=i; } FOR(i,1,n) { sl(a[i]); if(!(a[i]%p)) qw++; else b[id[a[i]%p]].x+=1.0; } er=m=p-1; for(m=er+m,er=1;er<=m;er<<=1); fft(b,1,er); FOR(i,0,er) b[i]=b[i]*b[i]; fft(b,-1,er); for(int i=0;i<2*p;i++) ans[i%(p-1)]+=(ll)(b[i].x+0.2); //cout<<ans[id[1]]<<endl; for(int i=1;i<=n;i++) { if(a[i]>=p) puts("0"); else if (a[i]==0) printf("%lld\n",2*qw*n-qw*qw); else printf("%lld\n",ans[id[a[i]]]); } return 0; }