快速数论变换(NTT)

今天的A题,裸的ntt,但我不会,于是白送了50分。

于是跑来学一下ntt。

题面很简单,就懒得贴了,那不是我要说的重点。

重点是NTT,也称快速数论变换。

在很多问题中,我们可能会遇到在模意义下的多项式乘法问题,这时传统的快速傅里叶变换可能就无法满足要求,这时候快速数论变换就派上了用场。

考虑快速傅里叶变换的实现,利用单位复根的特殊性质来减少运算,而利用的,就是dft变换的循环卷积特性。于是考虑在模意义下同样具有循环卷积特性的东西。

考虑在模p意义下(p为特定的质数,满足p=c?2n+1)

我们令p的一个原根为g,于是类比fft,我们的单位根为gp?1n,然后其它的处理都类比fft。

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef double db;

const int inf=0x3f3f3f3f;

int getint()
{
    int f=1,g=0;char c=getchar();
    while(c<‘0‘ || c>‘9‘){if(c==‘-‘)f=-1;c=getchar();}
    while(c>=‘0‘ && c<=‘9‘)g=(g<<3)+(g<<1)+c-‘0‘,c=getchar();
    return f*g;
}

const int maxn=1<<16;
const int G=7;
const int mod=950009857;

int inv;
int w[2][maxn];
int N,m,k;
int rev[maxn];
int n;
int cnt;

ll power(ll x,ll y)
{
    ll res=1ll;
    for(;y;y>>=1,x=(x*x)%mod)
    {
        if(y&1)res=res*x%mod;
    }
    return res;
}

void init()
{
    for(n=1;n<N<<1;n<<=1,cnt++);inv=power(n,mod-2);
    w[0][0]=w[0][n]=w[1][0]=w[1][n]=1;
    int g=power(G,(mod-1)/n);
    for(int i=1;i<=n-1;i++)
    {
        w[0][i]=(ll)w[0][i-1]*g%mod;
    }
    for(int i=0;i<=n;i++)
    {
        w[1][i]=w[0][n-i];
    }
    for(int i=0;i<=n;i++)
    {
        int temp=i;int pos=0;
        for(int j=1;j<=cnt;j++)
        {
            pos<<=1;pos |=temp&1;temp>>=1;
        }
        rev[i]=pos;
    }
}

void fft(int a[],int n,int v)
{
    int i,j,l;
    for(i=0;i<n;i++)
    {
        if(i>rev[i])swap(a[i],a[rev[i]]);
    }
    for(i=2;i<=n;i<<=1)
    {
        int mid=i>>1;
        for(j=0;j<n;j+=i)
        {
            for(l=0;l<mid;l++)
            {
                int t=(ll)a[j+l+mid]*w[v][(n/i)*l]%mod;
                a[j+l+(mid)]=((ll)a[j+l]-t+mod)%mod;
                a[j+l]=((ll)a[j+l]+t)%mod;
            }
        }
    }
}

int main()
{
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-15 01:43:44

快速数论变换(NTT)的相关文章

快速数论变换NTT模板

51nod 1348 乘积之和 #include <cmath> #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <queue> #include <map> #include <bitset> #include <set>

快速数论变换模板(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,求所有可以生成出的,且满足数列中

数学(论)里的一些定理(莫比乌斯反演,傅立叶变换,数论变换...)

莫比乌斯反演 莫比乌斯反演在数论中占有重要的地位,许多情况下能大大简化运算.那么我们先来认识莫比乌斯反演公式. 定理:和是定义在非负整数集合上的两个函数,并且满足条件,那么我们得到结论 在上面的公式中有一个函数,它的定义如下: (1)若,那么 (2)若,均为互异素数,那么 (3)其它情况下 对于函数,它有如下的常见性质: (1)对任意正整数有 (2)对任意正整数有 线性筛选求莫比乌斯反演函数代码. void Init() { memset(vis,0,sizeof(vis)); mu[1] =