题解 大天桥
因为太困了赛时并没有认真做这个题
- 有些多项式真的是可以手动求逆的
- 关于 \(x\) 的非整数次多项式(主要指 \(F(x)=\sqrt{a+bx}\),\(a, b\) 为常数)一类的东西可以牛顿二项式定理展开
- 可以使用分子/分母有理化让未知数在分式上来回挪
发现是要计算有多少种染色方案能建立天桥
把天桥看成有色括号序列,那么可以枚举最后一个括号所在的括号大小
令 \(f_i\) 为有 \(i\) 对括号时的答案,\(g_i\) 为有 \(i\) 对括号且有一种颜色不能选时的方案数
那么
\[f_i=k\sum\limits_{j=0}^{i-1}g_jf_{i-j-1}
\]
\[g_i=(k-1)\sum\limits_{j=0}^{i-1}g_jg_{i-j-1}
\]
这样就可以分治 NTT 了
然后考虑怎么优化:
需要 \(O(n)\),那么可能需要手动多项式求逆
尝试求出 \(G(x)=\sum g_ix^i\) 的封闭形式
发现
\[\begin{aligned}
G(x)&=1+(k-1)\sum\limits_{i=1}\sum\limits_{j=0}^{i-1}g_jg_{i-j-1}\\
&=1+(k-1)x\sum\limits_{i=0}\sum\limits_{j=0}g_ig_j\\
&=1+(k-1)xG^2(x)
\end{aligned}\]
于是
\[x(k-1)G^2(x)-G(x)+1=0
\]
扔进求根公式里,得
\[G(x)=\frac{1\pm\sqrt{1-4x(k-1)}}{2x(k-1)}
\]
只有一个根是合法的,是哪一个呢?
发现现在我们知道 \([x^0]G(x)=0\),那么尝试代入验证一下
但是直接代入会让分母为 0,需要先利用 \((a+b)(a-b)=a^2-b^2\) 分母有理化
可以得到
\[G(x)=\frac{2}{1\pm\sqrt{1-4x(k-1)}}
\]
因为
\[\lim\limits_{x\to 0}\frac{2}{1+\sqrt{1-4x(k-1)}}=\frac{2}{1+\sqrt{1}}=1=[x^0]G(x)
\]
所以可以舍去另一个不合法的根
得到
\[G(x)=\frac{2}{1-\sqrt{1-4x(k-1)}}
\]
同理得
\[F(x)=\frac{1}{1-kxG(x)}
\]
这个根号带着十分麻烦而且也不太能拆,所以可以设一个 \(u=\sqrt{1-4x(k-1)}\)
此时将 \(G\) 代入 \(F\) 得
\[F(x)=\frac{2k-2}{ku+k-2}
\]
然而这个东西仍然不能 \(O(n)\) 算
要想 \(O(n)\),就要把多项式求逆去掉
将分母有理化得
\[F(x)=\frac{ku-k+2}{2(1-k^2x)}
\]
令 \(H=\frac{ku-k+2}{2}\),那么 \((1-k^2x)F=H\)
发现这样的话 \(f_i=h_i+k^2f_i-1\),就可以线性求出了
那么现在要线性求出 \(H\)
与 Catalan 数类似的,使用牛顿二项式定理拆式子
\[\begin{aligned}
u&=\sqrt{1-4x(k-1)}\\
&=(1-4x(k-1))^{\frac{1}{2}}\\
&=\sum\limits_{i=0}\binom{\frac{1}{2}}{i}(-4x(k-1))^i\\
&=1+\sum\limits_{i=0}\frac{(\frac{1}{2})^{\underline{i}}}{i!}(-4x(k-1))^i\\
\end{aligned}\]
然后求这个 \(\dfrac{(\frac{1}{2})^{\underline{i}}}{i!}\)
\[\frac{(\frac{1}{2})^{\underline{i}}}{i!}=(-1)^{i-1}\frac{1}{2^i}\frac{(2i-3)!!}{i!}
\]
拆一下双阶乘
\[(2i-3)!!=\frac{(2i-2)!}{(2i-2)(2i-4)\cdots 2}=\frac{(2i-2)!}{2^{i-1}(i-1)!}
\]
再大力回代得到
\[u=1-\sum\limits_{i\geqslant 1}\frac{2(2i-2)!(k-1)^i}{(i-1)!i!}
\]
再代入 \(H\) 得到
\[H=1-\sum\limits_{i\geqslant 1}\frac{(2i-2)!k(k-1)^i}{(i-1)!i!}
\]
于是可以 \(O(n)\) 求出答案
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 10000010
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline ll read() {
ll ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n;
ll k, mod;
namespace force{
ll f[N], g[N];
void solve() {
f[0]=g[0]=1;
for (int i=1; i<=n; ++i) {
for (int j=0; j<i; ++j) {
f[i]=(f[i]+g[j]*f[i-j-1])%mod;
g[i]=(g[i]+g[j]*g[i-j-1])%mod;
}
f[i]=f[i]*k%mod;
g[i]=g[i]*(k-1)%mod;
}
printf("%lld\n", (f[n]%mod+mod)%mod);
}
}
namespace task1{
ll fac[N], inv[N], inv2[N], f[N], h[N];
void solve() {
fac[0]=fac[1]=1; inv[0]=inv[1]=1; inv2[0]=inv2[1]=1; h[0]=f[0]=1;
for (int i=2; i<=2*n; ++i) fac[i]=fac[i-1]*i%mod;
for (int i=2; i<=2*n; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
for (int i=2; i<=2*n; ++i) inv2[i]=inv2[i-1]*inv[i]%mod;
ll tem=k;
for (int i=1; i<=n; ++i) {
tem=tem*(k-1)%mod;
h[i]=-fac[2*i-2]*inv2[i]%mod*inv2[i-1]%mod*tem%mod;
}
for (int i=1; i<=n; ++i) f[i]=(h[i]+k*k%mod*f[i-1])%mod;
printf("%lld\n", (f[n]%mod+mod)%mod);
}
}
signed main()
{
freopen("flyover.in", "r", stdin);
freopen("flyover.out", "w", stdout);
n=read()>>1; k=read(); mod=read(); k%=mod;
// force::solve();
task1::solve();
return 0;
}