[生成函数] CF848E Days of Floral Colours

“做多项式题就像嗑药,出多项式题就像贩毒......”

\(Solution\)

这药劲儿确实大,它有着神奇的魔力让我盯着这恶心的代码看一天。

打题半小时,调试一整天——针不戳

\(:(\)

\(^_\)

准备工作

进入正题。

因为这是一个对称的结构,考虑将其转化为序列上的问题。

观察发现,我们可以将染色方式分成以下四种:

\(1:\overbrace{1,\hat{2},1}\)

\(2:\overbrace{1,2,1},2\)

\(3:\overbrace{1,1}\)

\(4:\hat{1}\)

即:

  1. 首尾同色,中间的与对面小球(球就是花,下同)同色

  2. (1,3)(2,4)位小球同色

  3. 相邻的两个小球同色

  4. 与对面的小球同色

那么现在我们就可以开始dp了

dp部分

设:

\(g[i]\) 表示长度为\(i\)的序列,只有情况2,3的方案数

\(f_0[i]\) 表示首尾两端都为情况4,中间有i个球的方案产生的贡献

\(f_1[i]\) 表示首尾两端中一端为\(\begin{aligned}\frac 2 3\end{aligned}\)的情况1(这两种情况是对称的,贡献相等),另一端为情况4,中间有i个球的方案产生的贡献

\(f_2[i]\) 表示首尾两端都是\(\begin{aligned}\frac 2 3\end{aligned}\)的情况1,中间有i个球的方案产生的贡献

那么转移就很显然了:

\(\begin{aligned} g[i]&=g[i-2]+g[i-4]\\ f_0[i]&=g[i]i^2+\sum_{j=0}^{i-1}g[j]j^2f_0[i-j-1]+\sum_{j=0}^{i-3}g[j](j+1)^2f_1[i-j-3]\\ f_1[i]&=g[i](i+1)^2+\sum_{j=0}^{i-1}g[j](j+1)^2f_0[i-j-1]+\sum_{j=0}^{i-3}g[j](j+2)^2f_1[i-j-3]\\ f_2[i]&=g[i](i+2)^2+\sum_{j=0}^{i-1}g[j](j+1)^2f_1[i-j-1]+\sum_{j=0}^{i-3}g[j](j+2)^2f_2[i-j-3] \end{aligned}\)

解释一下式子

  • \(f_0\)式:

\(f_0\) 中的第一项表示没有对称点的方案产生的贡献,那么直接就是方案数(\(g[i]\))乘上每个方案的贡献(\(i^2\))就完事儿了;

第一个\(\sum\) 是在计算将第\(j+1\)个球染成情况4的贡献,也就是在位置\(j+1\)用情况4分段,那么前\(j\)个球即全部是情况2,3,贡献为\(g[j]j^2\),后面一半的贡献为\(f_0[i-j-1]\),相乘即可;

第二个\(\sum\) 是在计算将\((j,j+1,j+2)\)这三个球染成情况1的贡献,前半段的贡献为\(g[j](j+1)^2\)\(j+1\)是因为后面还有\(\frac 2 3\)的情况1中吊着1个球,即第j个球,所以要+1,),后半段的贡献为\(f_1[i-j-3]\),因为对于后半段而言,它的开始是\(\frac 2 3\)的情况1,所以要转化成\(f_1\)而不再是\(f_0\)

  • \(f_1\)式(这里算首端为情况1,因为是对称的,贡献一样,取首端为情况1来解释\(dp\)式子):

\(f_1\)中的第一项就不再解释了,+1的原因也同上(好吧稍微有点不同,+1的球从末尾变成了开头罢了);
第一个\(\sum\) 亦是在计算将\(j+1\)染成情况4的贡献,前半段的贡献为\(g[j](j+1)^2\),(+1的原因同上),后半段的贡献为\(f_0[i-j-1]\);

第二个\(\sum\) 计算将\((j,j+1,j+2)\)三个球染成情况1的贡献,前半段的贡献为\(g[j](j+2)^2\)(首尾两端都是情况1,都吊了一个球(第1个球和第j个球),所以要+2),后半段的贡献为\(f_1[i-j-3]\)(前1后4)

  • \(f_2\) 式不再赘述,原理相同。

然而我们上面考虑仅是在序列上的情况,而我们要处理的是一个环。

我们不妨令第1个球和第n+1个球的颜色相同(因为一定要有一组相对的球颜色相同,否则不产生贡献)

考虑我们处理换上的问题时常用的方法——枚举偏转角度

枚举这个环在位置i上又有一组相对的球颜色相同(即i和n+i的颜色相同),那么就可以让圆环偏转i次(如果偏转超过i次就会与“第二组相对而同色的球的位置小于i”的情况产生重复)。

我们有:

\(\begin{aligned}Ans=\sum_{i=2}^{n-2}i(i-1)^2(g[i-1]f_0[n-i-1]+2g[i-2]f_1[n-i-2]+g[i-3]f_2[n-i-3])\end{aligned}\)

稍微解释一下式子:

  • 第一个i,是乘上了偏转次数,\((i-1)^2\)即是前半段的贡献(总共有i-1个球)

  • 括号中的第一项是指第一第二对相对而同色的球,都是情况4的贡献

  • 第二项是指第一第二对相对而同色的球中,有一对是\(\frac 2 3\)的情况1,另一个是情况4的贡献,因为有"1:1,2:4"和"1:4,2:1"(如果前面都认真看下来的话,这么写应该看得懂吧......懒得再用冗长的文字解释了)两种情况,所以要乘2

  • 第三项是指第一第二对相对而同色的求中,都是\(\frac 2 3\)的情况1的贡献

\(dp\)完成喽!

直接\(dp\)\(f_0,f_1,f_2\),时间复杂度是\(\Theta(n^2)\)的。

生成函数表示转移

很容易看出前面求\(f_0,f_1,f_2\)时的式子可以写成卷积形式

先把几个dp数组写成生成函数形式:

\(\begin{aligned} G_0(x)&=\sum_{i=0}^\infty g[i]i^2x^i\\ G_1(x)&=\sum_{i=0}^\infty g[i](i+1)^2x^i\\ G_2(x)&=\sum_{i=0}^\infty g[i](i+2)^2x^i\\ F_0(x)&=\sum_{i=0}^\infty f_0[i]x^i\\ F_1(x)&=\sum_{i=0}^\infty f_1[i]x^i\\ F_2(x)&=\sum_{i=0}^\infty f_2[i]x^i \end{aligned}\)

改写刚刚的\(dp\)式:

\(\begin{aligned} F_0(x)&=G_0(x)+G_0(x)F_0(x)x+G_1(x)F_1(x)x^3\\ F_1(x)&=G_1(x)+G_1(x)F_0(x)x+G_2(x)F_1(x)x^3\\ F_2(x)&=G_2(x)+G_1(x)F_1(x)x+G_2(x)F_2(x)x^3 \end{aligned}\)

\(G_0,G_1,G_2\)是我们能够\(\Theta(n)\)求出来的

\(F_0,F_1\)的两个式子,可以构成一个二元一次方程组(把\(G\)\(x\)当作常数),那么我们就可以用\(G,x\)来表示出\(F_0,F_1\),那么我们就可以在\(\Theta(n\log n)\)的时间内求出\(F_0,F_1\)

\(F_2\)又可以用\(F_1\)来表示,\(F_1\)又是已知的,所以我们便能\(\Theta(n\log n)\)求出\(F_2\)

最后\(\Theta(n)\)求出\(Ans\)

然后就只剩下求解那个一元二次方程了(dirty works ~)

求解过程:

\(\begin{aligned} F_0(x)&=G_0(x)+G_0(x)F_0(x)x+G_1(x)F_1(x)x^3\\ (1-G_0(x)x)F_0(x)&=G_0(x)+G_1(x)F_1(x)x^3\\ F_0(x)&=\frac{G_0(x)+G_1(x)F_1(x)x^3}{1-G_0(x)x} \end{aligned}\)

  • 将其代入\(F_1\)式:

\(\begin{aligned} F_1(x)&=G_1(x)+G_1(x)F_0(x)x+G_2(x)F_1(x)x^3\\ F_1(x)&=G_1(x)+G_1(x)x\frac{G_0(x)+G_1(x)F_1(x)x^3}{1-G_0(x)x}+G_2(x)F_1(x)x^3\\ (1-\frac{G_1^2(x)x}{1-G_0(x)x}-G_2(x)x^3)F_1(x)&=G_1(x)+\frac{G_0(x)G_1(x)}{1-G_0(x)x}\\ F_1(x)&=\frac{G_1(x)+G_0(x)G_1(x)x-G_0(x)G_1(x)x}{1-G_0(x)-G_1(x)x^4-G_2(x)x^3+G_(x)G_2(x)x^4}\\ F_1(x)&=\frac{G_1(x)}{(G_0(x)x-1)(G_2(x)x^3-1)-G_1^2(x)x^4} \end{aligned}\)

  • \(F_1\)代入\(F_0\)式:

\(\begin{aligned} F_0(x)&=\frac{G_0(x)+G_1(x)F_1(x)x^3}{1-G_0(x)x}\\ F_0(x)&=\frac{G_0(x)[(G_0(x)x-1)(G_2(x)x^3-1)-G_1^2(x)x^4]+G1^2(x)x^3}{(1-G_0(x)x)[(G_0(x)x-1)(G_2(x)x^3-1)-G_1^2(x)x^4]}\\ F_0(x)&=\frac{-G_0(x)(G_2(x)x^3-1)+G_1^2(x)x^3}{(G_0(x)x-1)(G_2(x)x^3-1)-G_1^2(x)x^4} \end{aligned}\)

  • 重写\(F_2\)式:

\(\begin{aligned} F_2(x)&=G_2(x)+G_1(x)F_1(x)x+G_2(x)F_2(x)x^3\\ (1-G_2(x)x^3)F_2(x)&=G_2(x)+G_1(x)F_1(x)x\\ F_2(x)&=\frac{G_2(x)+G_1(x)F_1(x)x}{1-G_2(x)x^3} \end{aligned}\)

至此,我们成功得做到了\(\Theta(n\log n)\)求解问题


这题其实还有更神仙的做法,能够做到\(\Theta(n)\)求解(甚至更快?)

但是,我累了...就这样吧

本题式子很多、很恶心,难免会有我推错的地方,大家直接在评论区指正就好,也不用私信我让我改了,因为...大概这次\(NOIP\)(明天?)之后我就退役了吧,也不会再看私信了

至此——...

\(Code\)

#include<bits/stdc++.h>
#define ll long long
const int N=2e5+10,mod=998244353;
int a[N],b[N],c[N],d[N],f0[N],f1[N],f2[N],G[N],g[5][N],rev[N],n,L,ans;
using namespace std;
int power(int a,ll b){
	int res=1,c=a;
	while (b){
		if (b&1) res=1ll*res*c%mod;
		b>>=1,c=1ll*c*c%mod;
	}
	return res;
}
void Get(int n,int opt=1){
	L=opt?1:n;
	while (L<n) L<<=1;
	for (int i=0;i<L;i++) rev[i]=rev[i>>1]>>1|(i&1?L>>1:0);
}
void fft(int *a,int opt){
	for (int i=0;i<L;i++) if (rev[i]>i) swap(a[rev[i]],a[i]);
	for (int l=2;l<=L;l<<=1){
		int W=opt==1?power(3,(mod-1)/l):power(power(3,(mod-1)/l),mod-2);
		for (int i=0;i<L;i+=l)
			for (int j=0,w=1;j<l>>1;j++,w=1ll*w*W%mod){
				int x=a[i+j],y=1ll*a[i+j+l/2]*w%mod;
				a[i+j]=(x+y)%mod,a[i+j+l/2]=(x-y)%mod;
			}
	}
	for (int i=0,v=power(L,mod-2);i<L;i++) if (opt==-1) a[i]=1ll*a[i]*v%mod;
}
void Inv(int *f,int *g,int n){
	int c[N];
	f[0]=power(g[0],mod-2);
	memset(c,0,sizeof(c));
	for (int l=2;l<n<<1;l<<=1){
		Get(l<<1,0);
		for (int i=0;i<l;i++) c[i]=g[i];
		for (int i=l;i<L;i++) c[i]=0;
		fft(c,1),fft(f,1);
		for (int i=0;i<L;i++) f[i]=(2-1ll*c[i]*f[i]%mod)*f[i]%mod;
		fft(f,-1);
		for (int i=l;i<L;i++) f[i]=0;
	}
}
int main(){
	scanf("%d",&n);
	G[0]=G[2]=1;
	for (int i=4;i<=n;i+=2)
		G[i]=(G[i-2]+G[i-4])%mod,g[0][i]=1ll*G[i]*i%mod*i%mod,g[1][i]=1ll*G[i]*(i+1)%mod*(i+1)%mod,g[2][i]=1ll*G[i]*(i+2)%mod*(i+2)%mod;
	g[1][0]=1,g[2][0]=4,g[0][2]=4,g[1][2]=9,g[2][2]=16;
	Get((n+1)<<1);
	for (int i=0;i<=n;i++)
		a[i]=i<1?0:g[0][i-1],b[i]=i<3?0:g[2][i-3],c[i]=g[0][i],d[i]=g[1][i],f1[i]=g[1][i];
	a[0]--,b[0]--;
	fft(a,1),fft(b,1),fft(c,1),fft(d,1);
	for (int i=0;i<L;i++) a[i]=1ll*a[i]*b[i]%mod,b[i]=1ll*c[i]*b[i]%mod,d[i]=1ll*d[i]*d[i]%mod;
	fft(a,-1),fft(b,-1),fft(d,-1);
	for (int i=n+1;i<L;i++) a[i]=0,b[i]=0,d[i]=0;
	for (int i=0;i<L;i++) c[i]=(a[i]-(i<4?0:d[i-4]))%mod,f0[i]=((i<3?0:d[i-3])-b[i])%mod;
	for (int i=n+1;i<L;i++) c[i]=0;
	memset(d,0,sizeof(d));
	Inv(d,c,n+1);
	Get((n+1)<<1);
	fft(d,1),fft(f0,1),fft(f1,1);
	for (int i=0;i<L;i++) f0[i]=1ll*f0[i]*d[i]%mod,f1[i]=1ll*f1[i]*d[i]%mod;
	fft(f0,-1),fft(f1,-1);
	for (int i=n+1;i<L;i++) f0[i]=f1[i]=0;
	for (int i=0;i<L;i++) b[i]=g[1][i],c[i]=i<3?0:-g[2][i-3],d[i]=f1[i];
	c[0]++;
	fft(b,1),fft(d,1);
	for (int i=0;i<L;i++) a[i]=1ll*b[i]*d[i]%mod;
	fft(a,-1);
	for (int i=n+1;i<L;i++) a[i]=0;
	for (int i=0;i<=n;i++) f2[i]=(g[2][i]+(i<1?0:a[i-1]))%mod;
	memset(a,0,sizeof(a));
	memset(a,0,sizeof(a));
	Inv(a,c,n+1);
	Get((n+1)<<1);
	fft(f2,1),fft(a,1);
	for (int i=0;i<L;i++) f2[i]=1ll*f2[i]*a[i]%mod;
	fft(f2,-1);
	for (int i=n+1;i<L;i++) f2[i]=0;
	ans=1ll*(G[n-1]+G[n-3])*(n-1)%mod*(n-1)%mod*n%mod;
	for (int i=2;i<=n-2;i++)
		ans=(ans+1ll*i*(i-1)%mod*(i-1)%mod*((1ll*G[i-1]*f0[n-i-1]%mod+(i<3||i>n-3?0:1ll*G[i-3]*f2[n-i-3]%mod))%mod+2ll*G[i-2]*f1[n-i-2]%mod)%mod)%mod;
	printf("%d\n",(ans+mod)%mod);
	return 0;
}
//恶心人的东西,爬!
posted @ 2020-12-04 11:02  WR_Eternity  阅读(124)  评论(0编辑  收藏  举报