多项式全家桶

板子不太好,改天换一个。

现在差不多能用,注意当前范围是 \(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;
}
posted @ 2021-02-20 20:00  皮皮刘  阅读(41)  评论(0编辑  收藏  举报