多项式&生成函数做题记录

开坑!最后有我的多项式板子。

T1:AT_agc005_f

对于每一个 u 分别考虑。反面考虑,计算 u 不被放进点集的方案数。于是我们可以得到 u 的贡献为:

(nk)(nsizuk)vsonu(sizvk)

然后我们考虑直接求和,可得:

f(k)=n×(nk)(urt(sizuk)+(nsizuk))

然后我们考虑用一个桶 cnti 表示有多少个 sizu=insizu=i。然后我们继续化简式子,得:

f(k)=n×(nk)i=kncnti×(ik)=n×(nk)i=kncnti×i!(ik)!×k!=n×(nk)1k!i=kncnti×i!(ik)!=n×(nk)1k!i=knkcntk+i×1i!×(i+k)!

此时我们令 g(x)=1x!,f(x)=(nx)!×cntnx。所以:

f(k)=n×(nk)1k!i=0nkg(i)f(nik)

这个式子就可以直接用 NTT 算啦!

T2:P4173

FFT 匹配字符串。

考虑定义一个函数 dis(S,T)=i=0n1(AiBi)2×Ai×Bi。容易发现,当 Ai==BiAi,Bi 中任意一个是通配符时,dis(S,T)=0

那么 AB 能匹配的条件就是 fi=dis(A,B[im+1,i])=0。考虑拆开 fi,得:

fi=j=0iAj3Bij2j=0iAj2Bij+j=0iAjBij3

然后 3 次 FFT 就行啦!

T3:P4199

发现直接求出答案十分不好求,于是可以先求先求出位置关于某根轴对称的回文子序列数量然后再减掉回文串的数量即可。

回文串数量直接用 Manacher 即可,接下来考虑如何求出关于某根轴对称的回文子序列数量。

定义 fi=j=0iSj=S2×ij。然后根据二项式定义可得第 i 个位置的答案即为 2fi1。那么问题就变为了 fi 怎么求。

此时我们构造 gi=[Si==a]hi=[Si==b],那么我们就可以得到:

f=gg+hh

然后就做完啦!

T:my poly

namespace Poly
{
	int qpow(int a,int b)
	{
		int res = 1;
		while(b)
		{
			if(b & 1)res = res * a % mod;
			a = a * a % mod;b >>= 1;
		}
		return res;
	}
	void Der(int *f,int *g,int len)
	{
		for(int i = 0;i < len;i++)g[i] = f[i + 1] * (i + 1) % mod;
		g[len - 1] = 0;
	}
	void Int(int *f,int *g,int len)
	{
		for(int i = 1;i < len;i++)g[i] = f[i - 1] * qpow(i,mod - 2) % mod;
		g[0] = 0;
	}
	void FFT(int *a,int x,int K)
	{
		static int rev[maxn],lst;
		int n = 1 << x;
		if(n != lst)
		{
			for(int i = 0;i < n;i++)rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << x - 1);
			lst = n;
		}
		for(int i = 0;i < n;i++)if(i < rev[i])swap(a[i],a[rev[i]]);
		for(int i = 1;i < n;i <<= 1)
		{
			int tmp = i << 1,wn = qpow(3,(mod - 1) / tmp);
			if(K == -1)wn = qpow(wn,mod-2);
			for(int j = 0;j < n;j += tmp)
			{
				int w = 1;
				for(int k = 0;k < i;k++,w = w * wn % mod)
				{
					int x = a[j + k],y = w * a[i + j + k] % mod;
					a[j + k] = (x + y) % mod;a[i + j + k] = (x - y + mod) % mod;
				}
			}
		}
		if(K == -1)
		{
			int inv = qpow(n,mod - 2);
			for(int i = 0;i < n;i++)a[i] = a[i] * inv % mod;
		}
	}
	void Inv(int *f,int *g,int len)
	{
		static int A[maxn];
		if(len == 1)return g[0] = qpow(f[0],mod - 2),void();
		Inv(f,g,len >> 1);copy(f,f + len,A);
		int x = log2(len << 1),n = 1 << x;
		fill(A + len,A + n,0);fill(g + (len >> 1),g + n,0);
		FFT(A,x,1);FFT(g,x,1);
		for(int i = 0;i < n;i++)g[i] = (mod + 2 - A[i] * g[i] % mod) * g[i] % mod;
		FFT(g,x,-1);fill(g + len,g + n,0);
	}
	const int inv2 = (mod + 1) / 2;
	void Sqrt(int *f,int *g,int len)
	{
		static int A[maxn],B[maxn];
		if(len == 1)return g[0] = sqrt(f[0]),void();
		Sqrt(f,g,len >> 1);Inv(g,B,len);
		copy(f,f + len,A);
		int x = log2(len << 1),n = 1 << x;
		fill(A + len,A + n,0);fill(B + len,B + n,0);
		fill(g + (len >> 1),g + n,0);
		FFT(A,x,1);FFT(B,x,1);FFT(g,x,1);
		for(int i = 0;i < n;i++)g[i] = (g[i] + A[i] * B[i] % mod) % mod * inv2 % mod;
		FFT(g,x,-1);fill(g + len,g + n,0);
	}
	void Ln(int *f,int *g,int len)
	{
		static int A[maxn],B[maxn];
		Der(f,A,len),Inv(f,B,len);
		int x = log2(len << 1),n = 1 << x;
		fill(A + len,A + n,0);fill(B + len,B + n,0);
		FFT(A,x,1);FFT(B,x,1);
		for(int i = 0;i < n;i++)A[i] = A[i] * B[i] % mod;
		FFT(A,x,-1);Int(A,g,len);
	}
	void Exp(int *f,int *g,int len)
	{
		static int A[maxn];
		if(len == 1)return g[0] = 1,void();
		int x = log2(len << 1),n = 1 << x;
		Exp(f,g,len >> 1);
		fill(A + len,A + n,0);fill(g + (len >> 1),g + n,0);
		Ln(g,A,len);
		A[0] = (f[0] + 1 - A[0] + mod) % mod;
		for(int i = 1;i < len;i++)A[i] = (f[i] - A[i] + mod) % mod;
		FFT(A,x,1);FFT(g,x,1);
		for(int i = 0;i < n;i++)g[i] = g[i] * A[i] % mod;
		FFT(g,x,-1);fill(g + len,g + n,0);
	}
	void Pow(int *f,int len,int k)
	{
		static int A[maxn];
		Ln(f,A,len);
		for(int i = 0;i < len;i++)A[i] = A[i] * k % mod;
		Exp(A,f,len);
	}
}using namespace Poly;
posted @   sqrtqwq  阅读(6)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示