关于傅里叶变换NTT(FNT)的周边

NTT:快速数论变化,对于FFT精度减少的情况,NTT可以避免但是会慢一点,毕竟是数论有Mod,和快速米

引用:http://blog.csdn.net/zz_1215/article/details/40430041

周边介绍。

利用原根,在ZP整数域(后悔没学好《信息安全数学基础》

原根介绍:http://baike.baidu.com/link?url=2gVDOcvJL0eTySKDiwFaDE7hNOTSJ087eGtv42QCt8tYEJZyUMXb6Eb40n0E0ygRoj4unNtEwukv3AFD1IEeia

然后对于一个整数域中的值分别对应一个数,具体看下这类数学书,用来替代单位根

对于一个P(素数)

比较快的一种方法找原根:http://blog.csdn.net/zhang20072844/article/details/11541133 (ORZ

大概是对于P的一个大于1的因子满足G^因子%P==1,那么就不是原根,原根很小。

其他跟FFT没区别。

其实傅里叶变化关键还是能够化成卷积的形式(这里只是处理普通和答案要求Mod的时候)

要求答案的逆,和除法,要看Picks的博客:

NTT:

#include<iostream>

#include<string.h>
#include<stdio.h>
#include<math.h>

using namespace std;
typedef long long ll;
const int N=1<<18;
const int P=998244353;
const int G=3;
const int NUM=20;
ll wn[NUM],a[N],b[N];
char A[N],B[N];

ll Pow(ll a,ll b,ll m)
{
   ll ans=1;
   a%=m;
   while (b)
   {
      if (b&1) ans=ans*a%m;
      a=a*a%m;
      b/=2;
   }
   return ans;
}

void Getwn()
{
   for (int i=0;i<NUM;i++)
   {
      int t=1<<i;
      wn[i]=Pow(G,(P-1)/t,P);
   }
}

void Rader(ll a[],int len)
{
   int j=len>>1;
   for (int i=1;i<len-1;i++)
   {
      if (i<j) swap(a[i],a[j]);
      int k=len>>1;
      while (j>=k)
      {
         j-=k;
         k>>=1;
      }
      if (j<k) j+=k;
   }
}

void NTT(ll a[],int len,int on)
{
   Rader(a,len);
   int id=0;
   for (int h=2;h<=len;h<<=1)
   {
      id++;
      for (int j=0;j<len;j+=h)
      {
         ll w=1;
         for (int k=j;k<j+h/2;k++)
         {
            ll u=a[k]%P;
            ll t=w*(a[k+h/2]%P)%P;
            a[k]=(u+t)%P;
            a[k+h/2]=((u-t)%P+P)%P;
            w=w*wn[id]%P;
         }
      }
   }

if (on==-1)
   {
      for (int i=1;i<len/2;i++)
      swap(a[i],a[len-i]);
      ll inv=Pow(len,P-2,P);
      for (int i=0;i<len;i++)
      a[i]=a[i]%P*inv%P;
   }
}
void Conv(ll a[],ll b[],int n)
{
   NTT(a,n,1);
   NTT(b,n,1);
   for (int i=0;i<n;i++)
   a[i]=a[i]*b[i]%P;
   NTT(a,n,-1);
}

int pan(char s[],char ss[])
{
   int len=strlen(s);
   len--;
   while (s[len]==‘0‘&&len>=0) len--;
   if (len<0) return 1;

len=strlen(ss);
   len--;
   while (ss[len]==‘0‘&&len>=0) len--;
   if (len<0) return 1;
   return 0;
}
int main()
{
   Getwn();
   while (scanf("%s%s",A,B)!=EOF)
   {
      if (pan(A,B))
      {
       puts("0");
       continue;
      }
      int len=1;
      int lenA=strlen(A);
      int lenB=strlen(B);
      while (len<=2*lenA||len<=2*lenB) len<<=1;
      for (int i=0;i<lenA;i++)
      A[len-1-i]=A[lenA-1-i];
      for (int i=0;i<len-lenA;i++) A[i]=‘0‘;

for (int i=0;i<lenB;i++)
      B[len-1-i]=B[lenB-1-i];
      for (int i=0;i<len-lenB;i++) B[i]=‘0‘;
      for (int i=0;i<len;i++) a[len-1-i]=A[i]-‘0‘;
      for (int i=0;i<len;i++) b[len-1-i]=B[i]-‘0‘;
      Conv(a,b,len);

int t=0;
      for (int i=0;i<len;i++)
      {
         a[i]+=t;
         if (a[i]>9)
         {
            t=a[i]/10;
            a[i]%=10;
         }
         else t=0;
      }
      len--;
      while (a[len]==0) len--;
      for (int i=len;i>=0;i--) printf("%d",a[i]);
      puts("");
   }
   return 0;
}

时间: 2024-11-28 23:26:02

关于傅里叶变换NTT(FNT)的周边的相关文章

FFT/NTT做题方法与调试技巧(+提高码题效率的一些想法)

(其实本文应该写成了"结合FFT讨论的调试技巧+码题方法",语文不好一写文章就偏题QAQ) 有意见欢迎提出,有遗漏欢迎补充! FFT(快速傅里叶变换)/NTT(数论变换)是卷积运算常见而实用的优化 但是FFT/NTT的处理过程并不像暴力运算(差不多是多项式乘法)那样能够直观地反映卷积结果的实时变化. 因此在使用FFT时将会或多或少地加大调试的难度. 如果调试程序时直接跟踪变量,每步手算结果比对,不仅会耽误大量时间,而且效果可能并不理想. 直接肉眼查错效率可能也不太高. 但也正由于FFT

快速数论变换(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

[学习笔记] 多项式与快速傅里叶变换(FFT)基础

引入 可能有不少OIer都知道FFT这个神奇的算法, 通过一系列玄学的变化就可以在 $O(nlog(n))$ 的总时间复杂度内计算出两个向量的卷积(或者多项式乘法/高精度乘法), 而代码量却非常小. 博主一年半前曾经因COGS的一道叫做"神秘的常数 $\pi$"的题目而去学习过FFT, 但是基本就是照着板子打打完并不知道自己在写些什么鬼畜的东西OwO 不过...博主这几天突然照着算法导论自己看了一遍发现自己似乎突然意识到了什么OwO然后就打了一道板子题还1A了OwO再加上午考试差点AK

快速数论变换(NTT)

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

多精度里FNT和SSA的点滴

多精度里FNT和SSA的点滴. Karatsuba,TOOM3,4.5...Toom-Cook可以看成是插值算法的逐步扩展. 比如TOOM3, 对Q(x),x=取5个不同值,即可一矩阵(行列式) 通过解上面矩阵既可以得到A,B,C,D,E,即Q(x)多项式系数. 这个推广后即是Toom-Cook算法. FFT则是Toom-Cook对取值的一个特化. 对于长度为N的FFT,其取值为复数域内N次方根, 就是一个范德蒙德(Vandermonde)矩阵. 其求解只需要nlogn就可以了.具体的解法随便一

51Nod 快速傅里叶变换题集选刷

打开51Nod全部问题页面,在右边题目分类中找到快速傅里叶变换,然后按分值排序,就是本文的题目顺序. 1.大数乘法问题 这个……板子就算了吧. 2.美妙的序列问题 长度为n的排列,且满足从中间任意位置划分为两个非空数列后,左边的最大值>右边的最小值.问这样的排列有多少个%998244353. 多组询问,n,T<=100000. 题解:经过分析可知,不合法的排列一定存在这样一种划分: 我们考虑答案=f[i]=i!-不合法排列个数. 形如 2 1 3 4 6 5 这种排列,会有三种划分方式不合法(

【转】快速傅里叶变换(FFT)详解

目录 前言 多项式 系数表示法 点值表示法 复数 向量 圆的弧度制 平行四边形定则 复数 运算法则 单位根 单位根的性质 快速傅里叶变换 快速傅里叶逆变换 理论总结 递归实现 迭代实现 本文只讨论FFT在信息学奥赛中的应用 文中内容均为个人理解,如有错误请指出,不胜感激 回到顶部 前言 先解释几个比较容易混淆的缩写吧 DFT:离散傅里叶变换->O(n2)O(n2)计算多项式乘法 FFT:快速傅里叶变换->O(n?log(n)O(n?log?(n)计算多项式乘法 FNTT/NTT:快速傅里叶变换

[拉格朗日反演][FFT][NTT][多项式大全]详解

1.多项式的两种表示法 1.系数表示法 我们最常用的多项式表示法就是系数表示法,一个次数界为\(n\)的多项式\(S(x)\)可以用一个向量\(s=(s_0,s_1,s_2,\cdots,s_n-1)\)系数表示如下:\[S(x)=\sum_{k=0}^{n-1}s_kx^k\] 系数表示法很适合做加法,可以在\(O(n)\)的时间复杂度内完成,表达式为:\[S(x)=A(x)+B(x)=\sum_{k=0}^{n-1}(a_k+b_k)x^k\] 当中\[s_k=a_k+b_k\] 但是,系数