快速数论变换NTT模板

51nod 1348 乘积之和

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <bitset>
#include <set>
const int maxlongint=2147483647;
const long long mo=100003;
const int N=300005;
using namespace std;
long long mod[2]={998244353,1004535809},M=mod[0]*mod[1];
long long f[N],g[N],f1[N],g1[N],h[22][N],W[2][N],ny;
int a[N],n,q;
long long poww(long long x,int y,int z)
{
    long long s=1;
    for(;y;y>>=1,x=x*x%mod[z])
        if(y&1) s=s*x%mod[z];
    return s;
}
long long mul(long long x,int y)
{
    long long s=0;
    for(;y;y>>=1,x=(x+x)%M)
        if(y&1) s=(s+x)%M;
    return s;
}
void NTT(long long *f,int len,int type,int z)
{
    for(int i=0,p=0;i<len;i++)
    {
        if(i<p) swap(f[i],f[p]);
        for(int j=len>>1;(p^=j)<j;j>>=1);
    }
    for(int i=2;i<=len;i<<=1)
    {
        int half=i>>1,pe=len/i;
        for(int j=0;j<half;j++)
        {
            long long w=!type?W[z][pe*j]:W[z][len-pe*j];
            for(int k=j;k<len;k+=i)
            {
                long long x=f[k],y=w*f[k+half]%mod[z];
                f[k]=(x+y)%mod[z],f[k+half]=(x-y+mod[z])%mod[z];
            }
        }
    }
    if(type)
    {
        ny=poww(len,mod[z]-2,z);
        for(int i=0;i<len;i++) f[i]=f[i]*ny%mod[z];
    }
}
long long CRT(int i)
{
    long long x0=poww(mod[1],mod[0]-2,0),x1=poww(mod[0],mod[1]-2,1);
    return (mul(f[i]*mod[1]%M,x0%M)+mul(f1[i]*mod[0]%M,x1%M))%M%mo;
}
void dc(int l,int r,int deep)
{
    if(l==r)
    {
        h[deep][0]=1,h[deep][1]=a[l]%mo;
        return;
    }
    int mid=(l+r)>>1,fn;
    for(fn=1;fn<=r-l+1;fn<<=1);

    dc(l,mid,deep+1);

    for(int i=0;i<fn;i++) h[deep][i]=h[deep+1][i],h[deep+1][i]=0;

    dc(mid+1,r,deep+1);

    W[0][0]=W[1][0]=1,W[0][1]=poww(3,(mod[0]-1)/fn,0),W[1][1]=poww(3,(mod[1]-1)/fn,1);
    for(int i=2;i<=fn;i++) W[0][i]=W[0][i-1]*W[0][1]%mod[0],W[1][i]=W[1][i-1]*W[1][1]%mod[1];

    for(int i=0;i<fn;i++) f[i]=f1[i]=g[i]=g1[i]=0;
    for(int i=0;i<=mid-l+1;i++) f[i]=f1[i]=h[deep][i];
    for(int i=0;i<fn;i++) h[deep][i]=0;
    for(int i=0;i<=r-mid;i++) g[i]=g1[i]=h[deep+1][i];
    for(int i=0;i<fn;i++) h[deep+1][i]=0;

    NTT(f,fn,0,0),NTT(f1,fn,0,1);
    NTT(g,fn,0,0),NTT(g1,fn,0,1);
    for(int i=0;i<fn;i++) f[i]=f[i]*g[i]%mod[0],f1[i]=f1[i]*g1[i]%mod[1];
    NTT(f,fn,1,0),NTT(f1,fn,1,1);

    for(int i=0;i<fn;i++) h[deep][i]=CRT(i);
}
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    dc(1,n,0);
    for(int x;q--;)
    {
        scanf("%d",&x);
        printf("%lld\n",h[0][x]);
    }
}

原文地址:https://www.cnblogs.com/chen1352/p/9099495.html

时间: 2024-08-01 06:11:58

快速数论变换NTT模板的相关文章

快速数论变换(NTT)

今天的A题,裸的ntt,但我不会,于是白送了50分. 于是跑来学一下ntt. 题面很简单,就懒得贴了,那不是我要说的重点. 重点是NTT,也称快速数论变换. 在很多问题中,我们可能会遇到在模意义下的多项式乘法问题,这时传统的快速傅里叶变换可能就无法满足要求,这时候快速数论变换就派上了用场. 考虑快速傅里叶变换的实现,利用单位复根的特殊性质来减少运算,而利用的,就是dft变换的循环卷积特性.于是考虑在模意义下同样具有循环卷积特性的东西. 考虑在模p意义下(p为特定的质数,满足p=c?2n+1) 我

快速数论变换模板(NTT)

快速数论变化(NTT)是的原理其实和快速傅里叶变换是一样的原理. 对于形如m= c*2^n+1的费马素数,假设其原根为g.那么瞒住g^(m-1)==1  而且正好(m-1)能整除2^n的.所所以可以在模p域进行NTT变换.旋转因子为  g^((m-1)/n).其他的原理都和FFT的原理相同.这样可以解决特殊情况下FFT的浮点误差. /* * Author: islands * Created Time: 2015/7/30 9:25:47 * File Name: test.cpp */ #in

快速数论变换(NTT)

转自ACdreamers (http://blog.csdn.net/acdreamers/article/details/39026505) 在上一篇文章中 http://blog.csdn.net/acdreamers/article/details/39005227 介绍了用快速傅里叶变 换来求多项式的乘法.可以发现它是利用了单位复根的特殊性质,大大减少了运算,但是这种做法是对复数系数的矩阵 加以处理,每个复数系数的实部和虚部是一个正弦及余弦函数,因此大部分系数都是浮点数,我们必须做复数及

NTT(快速数论变换)用到的各种素数及原根

NTT(快速数论变换)用到的各种素数及原根 g是mod(r * 2 ^ k + 1)的原根 r * 2 ^ k + 1 r k g 3 1 1 2 5 1 2 2 17 1 4 3 97 3 5 5 193 3 6 5 257 1 8 3 7681 15 9 17 12289 3 12 11 40961 5 13 3 65537 1 16 3 786433 3 18 10 5767169 11 19 3 7340033 7 20 3 23068673 11 21 3 104857601 25 2

数论 (大数,小费马定理,欧拉定理,威尔逊定理,快速数论变换(NNT)模版)

1 Java大数 2 import java.util.*; 3 import java.math.*; 4 public class Main{ 5 public static void main(String args[]){ 6 Scanner cin = new Scanner(System.in); 7 BigInteger a, b; 8 9 //以文件EOF结束 10 while (cin.hasNext()){ 11 a = cin.nextBigInteger(); 12 b

模板 NTT 快速数论变换

NTT裸模板,没什么好解释的 这种高深算法其实也没那么必要知道原理 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define N (1<<17)+10 5 #define ll long long 6 using namespace std; 7 8 ll inv3,invl; 9 int r[N]; 10 ll A[N],B[N],C[N],mulwn[N],invw

BZOJ 3992 Sdoi2015 序列统计 快速数论变换

题目大意:给定n(n<=10^9),质数m(3<=m<=8000),1<=x=m,以及一个[0,m-1]区间内的集合S,求有多少长度为n的数列满足每个元素都属于集合S且所有元素的乘积mod m后=x 求原根,对S集合内每个元素取指标,然后搞出生成函数f(x) 那么答案就是(f(x))^n (mod x^(m-1),mod 1004535809) 上NTT用多项式快速幂搞一搞就好了 #include <cstdio> #include <cstring> #i

BZOJ 3992: [SDOI2015]序列统计 [快速数论变换 生成函数 离散对数]

3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1017  Solved: 466[Submit][Status][Discuss] Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S. 小C用这个生成器生成了许多这样的数列.但是小C有一个问题需要你的帮助:给定整数x,求所有可以生成出的,且满足数列中

快速傅立叶变换(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:快速傅立叶变换算法总