多项式全家桶
板子不太好,改天换一个。
现在差不多能用,注意当前范围是 \(10^5\) 级别以及 pre
函数的实现。
但是现在只有乘法、求逆、ln、exp。
//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std;
typedef long long LL;
const int MAXN = 1 << 18 | 5;
const int MOD = 998244353;
const int PHI = 998244352;
const int GINV = 332748118,G = 3;
int n;
int a[MAXN],b[MAXN],ans[MAXN];
LL Read()
{
LL x = 0,f = 1; char c = getchar();
while(c > '9' || c < '0'){if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
return x * f;
}
TT void Put1(T x)
{
if(x > 9) Put1(x/10);
putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
if(x < 0) putchar('-'),x = -x;
Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}
int inv[MAXN];
void init()
{
inv[0] = inv[1] = 1;
for(int i = 2;i < MAXN;++ i) inv[i] = 1ll * inv[MOD%i] * (MOD - MOD/i) % MOD;
}
int qpow(int x,int y)
{
int ret = 1;
while(y){if(y & 1) ret = 1ll * ret * x % MOD;x = 1ll * x * x % MOD;y >>= 1;}
return ret;
}
int rev[MAXN],len;
int pre(int L)
{
int l = -1; len = 1;
while(len < (L<<1)) len <<= 1,++l;
for(int i = 1;i < len;++ i) rev[i] = (rev[i>>1] >> 1) | ((i & 1) << l);
return len;
}
int Ad(int x){if(x >= MOD) x -= MOD;if(x < 0) x += MOD;return x;}
void NTT(int *a,int f)
{
for(int i = 0;i < len;++ i) if(i < rev[i]) swap(a[i],a[rev[i]]);
for(int i = 1;i < len;i <<= 1)
{
int w = qpow(f > 0 ? G : GINV,PHI / (i<<1));
for(int j = 0,p = i << 1;j < len;j += p)
for(int k = 0,mi = 1;k < i;++ k,mi = 1ll * mi * w % MOD)
{
int X = a[j+k],Y = 1ll * mi * a[i+j+k] % MOD;
a[j+k] = Ad(X+Y);
a[i+j+k] = Ad(X-Y+MOD);
}
}
if(f == -1) for(int i = 0,in = qpow(len,MOD-2);i < len;++ i) a[i] = 1ll * a[i] * in % MOD;
}
int tmp1[MAXN],tmp2[MAXN];
void polymul(int *a,int lena,int *b,int lenb,int *ret)//巨慢
{
pre(Max(lena,lenb));
for(int i = 0;i < len;++ i) if(i < lena) tmp1[i] = a[i]; else tmp1[i] = 0;
for(int i = 0;i < len;++ i) if(i < lenb) tmp2[i] = b[i]; else tmp2[i] = 0;
NTT(tmp1,1); NTT(tmp2,1);
for(int i = 0;i < len;++ i) ret[i] = 1ll * tmp1[i] * tmp2[i] % MOD;
NTT(ret,-1);
}
void polyinv(int *a,int *ret,int N)//还行
{
if(N == 1){ret[0] = qpow(a[0],MOD-2);return;}
polyinv(a,ret,(N+1)>>1); pre(N);
for(int i = 0;i < len;++ i) if(i < N) tmp1[i] = a[i]; else tmp1[i] = 0;
NTT(tmp1,1); NTT(ret,1);
for(int i = 0;i < len;++ i) ret[i] = (2ll * ret[i] - 1ll * tmp1[i] * ret[i] % MOD * ret[i] % MOD + MOD) % MOD;
NTT(ret,-1); for(int i = N;i < len;++ i) ret[i] = 0;
}
int ad[MAXN],tmp3[MAXN];
void polyln(int *a,int *ret,int N)//还行
{
pre(N); for(int i = 0;i < len;++ i) ad[i] = tmp3[i] = 0;
for(int i = 1;i < N;++ i) ad[i-1] = 1ll * i * a[i] % MOD;//导
polyinv(a,tmp3,N);
polymul(ad,N,tmp3,N,ret);
for(int i = N-1;i >= 1;-- i) ret[i] = 1ll * ret[i-1] * inv[i] % MOD;//积
// for(int i = N;i < len;++ i) ret[i] = 0;
ret[0] = 0;
}
int tmp4[MAXN],tmp5[MAXN];
void polyexp(int *a,int *ret,int N)//还行
{
if(N == 1) {ret[0] = 1;return;}//a[0] = 0;
polyexp(a,ret,(N+1) >> 1);
polyln(ret,tmp4,N); --tmp4[0]; //pre(N);
for(int i = 0;i < len;++ i) if(i < N) tmp4[i] = (MOD-tmp4[i]+a[i]) % MOD; else tmp4[i] = 0;
polymul(ret,N,tmp4,N,ret);
// for(int i = N;i < len;++ i) ret[i] = 0;
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
init();
// polyinv(a,ans,n);
// polyln(a,ans,n);
// polyexp(a,ans,n);
return 0;
}