关于傅里叶变换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<0return 1;

   len=strlen(ss);
   len--;
   while (ss[len]=='0'&&len>=0) len--;
   if (len<0return 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;
}

 

  

posted on 2015-09-18 01:03  forgot93  阅读(638)  评论(0编辑  收藏  举报

导航