A*B 原根+FFT优化

题目地址 https://loj.ac/problem/6156

#include <bits/stdc++.h>
const long long mod = 1e9+7;
const double ex = 1e-10;
#define inf 0x3f3f3f3f
using namespace std;
const double PI = acos(-1.0);
const int MAXN = 60044*4;
struct Complex{
    double x,y;
    Complex(double _x = 0.0,double _y =0.0){
        x = _x;y =_y;
    }
    Complex operator - (const Complex &b)const{
        return Complex(x-b.x,y-b.y);
    }
    Complex operator + (const Complex &b)const{
        return Complex(x+b.x,y+b.y);
    }
    Complex operator * (const Complex &b)const{
        return Complex(x*b.x - y*b.y,x*b.y + y*b.x);
    }
};
void change (Complex y[],int len){
    int i,j,k;
    for (i = 1,j = len/2;i<len -1;i++){
        if (i<j) swap(y[i],y[j]);
        k = len/2;
        while (j >= k){
            j-=k;
            k/=2;
        }
        if (j<k) j+=k;
    }
}
void fft(Complex y[],int len, int on)
{
    change(y,len);
    for (int h = 2; h<=len;h<<=1){
        Complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h));
        for (int j =0 ; j< len; j+=h){
            Complex w(1,0);
            for (int k = j;k < j+h/2;k++){
                Complex u = y[k];
                Complex t = w*y[k+h/2];
                y[k] = u+t;
                y[k+h/2] = u-t;
                w = w*wn;
            }
        }
    }
    if (on == -1)
        for (int i = 0; i<len; i++)
        y[i].x /= len;

}

Complex x1[MAXN];
long long x2[MAXN];
long long num[MAXN];
long long ans[MAXN/4];
long long quick_s(long long x,long long y,long long N){
    long long ans = 1;
    while (y){
        if (y % 2) ans = (ans * x) % N;
        x = (x*x) % N;
        y/=2;
    }
    return ans % N;
}
vector <long long> p;
int b[62345];
void getprime(int N){
    for (int i = 2;i<=N;i++){
        if ( b[i] == 0 ){
            p.push_back((long long)i);
            int j = 2;
            while (i*j <= N)
                b[i*j] = 1,j++;
        }
    }
}

int getroot(long long N){
    vector <long long> C;
    C.clear();
    long long t = N-1;
    for (long long i = 0; i<p.size() && p[i]*p[i] <= N; i++){
        if (t % p[i] == 0 && t!=1){
            C.push_back((N-1)/p[i]);
            while (t % p[i] == 0 && t!=1) t/=p[i];
        }
    }
    if (t!=1) C.push_back((N-1)/t);
    for (long long i = 2 ; i<=N; i++){
        int flag = 1;
        for (int j = 0 ; j< C.size() && flag ; j++ )
            if (quick_s(i,C[j],N) == 1&&C[j]!=N-1) flag = 0;
        if (flag && (quick_s(i,N-1,N) == 1)) return i;
    }
    return 0;
}
int main()
{
    getprime(60000);
    int T;
    scanf("%d",&T);
    while (T--){
        long long n,m;
        scanf("%lld%lld",&n,&m);
        long long  root = getroot(m);
        memset(num,0,sizeof(num));
        memset(x2,0,sizeof(x2));
        memset(ans,0,sizeof(ans));
        int len1 = m;
        for (int i = 1; i<=n; i++){
            int d;
            scanf("%d",&d);
            num[d%m]++;
        }
        int len = 1;
        while (len < len1*2) len <<=1;
        for (int i = 1; i<m;i++)
            x1[i] = Complex(num[quick_s(root,i,m)],0);
        for (int i = m ; i<len ; i++)
            x1[i] = Complex(0,0);
        x1[0] = Complex(0,0);
        fft(x1,len,1);
        for (int i = 0 ; i<len ; i++)
            x1[i] = x1[i] * x1[i];
        fft(x1,len,-1);

        ans[0] = num[0] * (num[0]-1)/2 + num[0] * (n-num[0]);
        printf("%d\n",ans[0]);
        for (int i = 0; i<=2*m;i++)
            x2[i] = (long long)(x1[i].x + 0.5);
        for (long long i = 1; i<m; i++){
            long long t = quick_s(root,i,m);
            x2[2*i] -= num[t] * num[t];
            x2[2*i-1]/=2;
            x2[2*i]/=2;
            x2[2*i] += (num[t] * (num[t] - 1)/2);
        }
        if (m==2){
            printf("%lld\n",n*(n-1)/2-ans[0]);
        }
        else{
            for (long long  i = 1; i<m ; i++){
                ans[quick_s(root,i,m)] = x2[i]+ x2[m-1+i];
            }
            for (int i = 1; i<m ; i++){
                printf("%lld\n",ans[i]);
            }
        }
    }
    return 0;
}
View Code

 

posted @ 2017-09-06 20:44  HITLJR  阅读(205)  评论(0编辑  收藏  举报