link。
首先如果 Ln≠n 则无解,以下默认 Ln=n。
记 li=i−Li+1,即最长连续段的左端点。
由一些基本常识,连续段的交、并、差仍是连续段;这可以推出所有 [li,i] 互相包含或相离(如果不满足,则无解)。
建出树形结构:根为 [1,n];对于 [li,i],如果 li=i 则它为叶子;否则它的儿子为 [li−1,i−1];[lli−1−1,li−1−1];…。
不难发现 [li,i] 子树内怎么定方案与外部无关,那么只需要考虑每个点的所有儿子如何分配方案,将所有点的贡献相乘即可。
也即,如果记 fi 表示有 i 个儿子的方案数,记 degi 表示 i 的儿子个数,则答案为 ∏ni=1fdegi。
然后我们进入 counting 环节。
先考虑 fn 的一个等价定义:长度为 n+1 的排列,其中 L1…n=1,Ln+1=n+1 的方案数。
比较难看出 {fn} 可能具有的递归结构,那么正难则反。
总方案数为 (n+1)!,其中不合法当且仅当根 [1,n+1]的儿子个数 <n。
注意我们只考虑了根,根以下的子树没有加以任何限制,所以贡献为子树大小的阶乘。
因此,如果记 G(x)=∑n>0n!xn,则有 fn=(n+1)!−∑n−1i=1fi[xn]Gi(x)。
以下依然记 G(x)=∑n>0n!xn。
事实上,如果记 F(x)=∑n≥0fnxn,则有一个组合意义更明显的式子:
F(G(x))=∑n≥0(n+1)!xn
即依据根的儿子个数,将所有 (n+1)! 种排列分类。
将右边也化成 G(x) 的形式,得到:xF(G(x))=G(x)。
如果记 H(x) 是 G(x) 的复合逆,则:F(x)=x/H(x)。
太好了,套用复合逆算法卡卡常说不定就过了。
注意到 G 是经典的微分有限。事实上,根据 gn=ngn−1+[n=1],有 G=x2G′+xG+x。
将 x 代换成 H(x):
G(x)=x2dG(x)dx+xG(x)+xx=H2dG(H)dH+Hx+Hx=H2dxdH+Hx+Hx=(x/F)2(1(x/F)′)+(x/F)x+(x/F)0=F2−xF′F−2xF+x2F′+xF′−F
我承认,最后一步跳得有点快。
取第 n 项,得到 0=∑ni=0fifn−i−∑ni=0i×fifn−i−2fn−1+(n−1)fn−1+nfn−fn。
那么有递推式 fn=∑n−1i=1(i−1)×fifn−i−(n−3)fn−1。
或者说 fn=∑n−2i=2(i−1)×fifn−i+(n−1)fn−1。
条件 f0=1。
之后再做个分治 fft 即可,复杂度 O(nlog2n)。
另一种推导方法:https://blog.csdn.net/qq_39972971/article/details/89408417 。
最后依然是求助环节:有没有懂哥愿意教教我 simple permutations 咋数啊。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
2020-05-13 @atcoder - ARC077F@ SS