多项式板子

#include <iostream>
using namespace std;
#define ll long long
const ll N = 1e5+50;
namespace NTT{
    const int P[3] = {469762049, 998244353, 167772161},//模数
    G = 3, //原根
    Gi[3] = {P[0] / G + 1, P[1] / G + 1, P[2] / G + 1};//逆元
    int R[N];
    inline int f_pow(int x, int y) {
        int ans = 1;
        while(y) {
            if(y & 1) ans = 1ll*ans * x % P[1];
            y >>= 1; x = 1ll*x * x % P[1];
        }
        return ans%P[1];
    }
    inline void ntt(int A[],int limit,int type){
        for(int i = 0;i < limit;i++)if(i < R[i])std::swap(A[i],A[R[i]]);
        for(int mid = 1;mid < limit;mid<<=1){
            int wn = f_pow(type == 1?G:Gi[1],(P[1]-1)/(mid<<1));//原根
            // if(type == -1) wn = f_pow(wn,mod-2);
            for(int len = mid<<1,pos = 0;pos < limit;pos+=len){
                int w = 1;
                for(int k = 0;k<mid;k++,w = 1ll*w*wn%P[1]){
                    //原根的操作与单位根类似
                    int x = A[pos+k],y = 1ll*w*A[pos+k+mid]%P[1];
                    A[pos+k] = (x+y)%P[1];
                    A[pos+k+mid] = (x-y+P[1])%P[1];
                }
            }
        }
        if(type == 1)return ;
        int inv_lim = f_pow(limit,P[1]-2);
        for(int i = 0;i < limit;i++) A[i] = 1ll*A[i]*inv_lim%P[1];
    }
    //多项式相乘
    inline void mul(int a[],int n,int b[],int m){
        int limit = 1, L = 0;
        while (limit <= n+m)limit <<= 1, L++;
        for (int i = 0; i < limit; i++)R[i] = R[i >> 1] >> 1 | ((i & 1) << (L - 1));
        ntt(a, limit, 1);ntt(b, limit, 1);
        for (int i = 0; i <= limit; i++) a[i] = 1ll*a[i] * b[i] % P[1];
        ntt(a, limit, -1);
    }
    //多项式求逆元
    inline void  inv(int a[],int b[],int n){//多项式求逆元
        static int c[N];
        if(n == 1){b[0] = f_pow(a[0],P[1]-2);return;}

        inv(a,b,(n+1)>>1);
        int limit = 1, L = 0;
        while (limit <= n+n)limit <<= 1, L++;
        for (int i = 0; i < limit; i++)R[i] = R[i >> 1] >> 1 | ((i & 1) << (L - 1));
        for(int i = 0; i < limit; ++i) {
            R[i] = (R[i >> 1] >> 1) | ((i & 1) ? (limit >> 1) : 0);
            c[i] = (i < n ? a[i] : 0);//只算到⌈n/2⌉,后面的全部为0;
        }
        ntt(c,limit,1),ntt(b,limit,1);
        for(int i = 0; i < limit; ++ i) {
            b[i] = (2ll - 1ll*c[i] * b[i] % P[1] + P[1]) % P[1] * b[i] % P[1];
        }
        ntt(b,limit,-1);
        fill(b+n,b+limit,0);
//        for(ll i = 0;i < n;i++)cout<<b[i]<<' ';
//        cout<<endl;
    }
    //多项式求导
    inline void dev(int a[], int b[], int n){
        for(int i = 1; i < n; ++ i)b[i - 1] = 1ll*i * a[i] % P[1];
        b[n - 1] = 0;
    }
    //多项式求积分
    inline void indev(int a[], int b[], int n){
        for(int i = 1; i < n; ++ i)b[i] = 1ll*a[i - 1] * f_pow(i, P[1] - 2) % P[1];
        b[0] = 0;
    }
    //多项式求对数
    inline void In(int a[],int b[],int n){
        static int A[N],B[N];
        fill(A,A+(n<<1),0),fill(B,B+(n<<1),0);
        inv(a,A,n),dev(a,B,n);
        mul(A,n,B,n);indev(A,b,n);
    }
}

上一篇:php 时间段查询排序分组


下一篇:【P2323 [HNOI2006]公路修建问题】题解