多项式板子
作者:互联网
#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);
}
}
标签:int,多项式,ll,ntt,板子,1ll,limit,ans 来源: https://www.cnblogs.com/Paranoid5/p/15569627.html