[生成函数] 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,3)(2,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;
}
//恶心人的东西,爬!