zoukankan      html  css  js  c++  java
  • 关于傅里叶变换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;
    }

      

  • 相关阅读:
    socketserver
    socket进阶
    socket基础
    反射
    subprocess模块
    面向对象高级特性
    面向对象基础
    字典的高级特性
    *号的妙用
    logging模块
  • 原文地址:https://www.cnblogs.com/forgot93/p/4818091.html
Copyright © 2011-2022 走看看