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;
}

时间: 2024-10-13 21:21:12

A*B 原根+FFT优化的相关文章

2018秦皇岛ccpc-camp Steins;Gate (原根+FFT)

因为给定的模数P保证是素数,所以P一定有原根. 根据原根的性质,若\(g\)是\(P\)的原根,则\(g^k\)能够生成\([1,P-1]\)中所有的数,这样的k一共有P-2个. 则\(a_i*a_j(mod\ P)=a_k\) 就可以转化为\(g^i*g^j(mod\ P) = g^{i+j}(mod\ P)=g^k\). 问题转化为了求有多少对有序的<i,j>满足 \((i+j)(mod\ (P-1)) = k\). 求出原根后,对\([1,P-1]\)中的每个数编号, 统计每个编号出现的

快速傅立叶变换(FFT)相关内容汇总

FFT是近年考察非常频繁的算法,与其相关的知识点也相当多样. 这里主要是资料汇总,内容补充和总结等.具体应用应在各大OJ上做相关题目. 目录: 概述 1. 前置技能:数学基础 1.1 多项式概念与运算. 1.2 微积分初步与泰勒展开 1.3 普通型生成函数与指数型生成函数 1.4 线性代数相关(矩阵,行列式与特征多项式) 1.5 组合数与伯努利数 1.6 常系数齐次线性递推 1.7 初等数论与初等代数 1.8 卷积概念与O(n^2)求法 1.9 拉格朗日插值法 2. FFT:快速傅立叶变换算法总

51nod 1348 乘积之和 分治 + fft

给出由N个正整数组成的数组A,有Q次查询,每个查询包含一个整数K,从数组A中任选K个(K <= N)把他们乘在一起得到一个乘积.求所有不同的方案得到的乘积之和,由于结果巨大,输出Mod 100003的结果即可.例如:1 2 3,从中任选1个共3种方法,{1} {2} {3},和为6.从中任选2个共3种方法,{1 2} {1 3} {2 3},和为2 + 3 + 6 = 11. 预处理 + O(1)回答 很容易想到用分治来做,这样在分治过程中需要一个dp,这个dp递推式是O(n^2)的, 所以复杂

fft练习

数学相关一直都好弱啊>_< 窝这个月要补一补数学啦, 先从基础的fft补起吧! 现在做了 道. 窝的fft 模板 (bzoj 2179) 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #define MAXN 200005 7 #define PI M_PI 8 usi

POJ3150【FFT】

转移很好用矩阵表示.然而矩阵乘法复杂度是O(n^3)的. 很容易发现转移矩阵是[循环矩阵].而且有一个美妙的性质:[循环矩阵 * 循环矩阵 = 循环矩阵]. 所以我们计算矩阵乘法的时候可以只计算第一行.剩下的可以由第一行递推得出. 一次乘法的复杂度降到了O(n^2).这是可以接受的. #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <ct

HDU 5730 Shell Necklace(CDQ分治+FFT)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5730 [题目大意] 给出一个数组w,表示不同长度的字段的权值,比如w[3]=5表示如果字段长度为3,则其权值为5,现在有长度为n的字段,求通过不同拆分得到的字段权值乘积和. [题解] 记DP[i]表示长度为i时候的答案,DP[i]=sum_{j=0}^{i-1}DP[j]w[i-j],发现是一个卷积的式子,因此运算过程可以用FFT优化,但是由于在计算过程中DP[j]是未知值,顺次计算复杂度是O(

FFT多项式乘法学习笔记

??其实我不知道我是否真的理解了FFT,但是我会用FFT优化多项式乘法了QAQ.. (以下大多摘自算导 前置知识 1. 多项式 ??在一个代数域F上,关于变量x的多项式定义为形式和形式表示的函数 A(x)=∑j=0n?1ajxj,其中a0-an?1为多项式各项的系数 2. 多项式的次数界 ??若多项式有非零系数的最高次项为xk,则称k为该多项式的次数,任何严格大于k的整数都是这个多项式的次数界. 3. 多项式的表示 (1)系数表示法 ??对于一个次数界为n的多项式A(x)来说,其系数表示法可以看

BZOJ3160 万径人踪灭 字符串 多项式 Manachar FFT

原文链接http://www.cnblogs.com/zhouzhendong/p/8810140.html 题目传送门 - BZOJ3160 题意 给你一个只含$a,b$的字符串,让你选择一个子序列,使得: $1.$位置和字符都关于某一条对称轴对称. $2.$不能是连续的一段. 问原来的字符串中能找出多少个这样的子序列.答案对$10^9+7$取模. 串长$\leq 10^5$. 题解 下面的讨论都在满足条件$1$的情况下进行. 首先,我们先不考虑条件$2$.然后再减掉不满足条件$2$的就可以了

[luogu4389]付公主的背包(FFT)

完全背包方案计数问题的FFT优化.首先写成生成函数的形式:对重量为V的背包,它的生成函数为$\sum\limits_{i=0}^{+\infty}x^{Vi}=\frac{1}{1-x^{V}}$于是答案就是$\prod \frac{1}{1-x^{V_k}}$.直接做显然会超时,考虑使用ln将乘法变为加法.https://www.cnblogs.com/cjyyb/p/10132855.html 1 #include<cmath> 2 #include<cstdio> 3 #in