数轴上连 n 条弦,共有 k 个交点的方案数
Posted alfalfa_w
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数轴上连 n 条弦,共有 k 个交点的方案数相关的知识,希望对你有一定的参考价值。
问题
数轴上有 \\(2n\\) 个点,考虑所有用 \\(n\\) 条弦将它们完美匹配的方案,有多少种方案会产生 \\(k\\) 个交点(不考虑三线共点)?
在 OEIS 上为A067311。
分析
本文主要是对这篇论文的翻译。
转化问题
首先我们考虑 DP。考虑生成函数,我们用 \\(z\\) 累计交点数。记 \\(F_i,j\\) 为考虑了前 \\(i\\) 个点,往后连了 \\(j\\) 条弦的生成函数。那么一条弦在 DP 中经历 \\(2\\) 个过程:“产生”和“闭合”,我们在闭合时累加交点数。假设往后连的 \\(j\\) 条弦中,我们选择从左往右第 \\(a\\) 条弦在 \\(i+1\\) 处闭合,那么会有 \\(z^j-a\\) 的贡献。因此,闭合的总贡献就是 \\(1+z+\\cdots+z^j-1 = (1-z^j)/(1-z)\\)。无论 DP 的路径如何,\\((1-z)^-1\\) 总是会乘恰好 \\(n\\) 次,所以可以留到最后再乘。我们可以写出 DP 的转移式:
答案为 \\((1-z)^-nF_2n,0\\)。
考虑把 DP 状态看作点,转移的路径看作折线,那么相当于枚举所有折线,对于一条折线,设所有\\
单位线段的“高度”为 \\(h_1,h_2,\\cdots,h_n\\),那么它对答案有 \\(\\prod (1-z^h_i)\\) 的贡献。
考虑把折线与有根树的 DFS 过程一一对应:/
单位线段看作入栈操作,\\
单位线段看作出栈操作。那么,树的每个非根结点都可能为“普通点”或“关键点”,对于一棵有 \\(r\\) 个关键点,关键点深度和为 \\(k\\) 的树,它对答案的贡献为 \\((-1)^rz^k\\)。
通过构造对合来抵消系数
对于一棵树,我们只保留所有关键点到根的路径的并(虚树),假设还剩下 \\(l\\) 条边。对于剩下 \\(l\\) 条边的虚树,考虑把它补全的方案数。相当于在原本的入栈-出栈序列中的 \\(2l+1\\) 个空隙中分别插入合法括号序列,把长度补到 \\(2n\\) 的方案数。又相当于长度为 \\(2n+2l\\) 的括号序列,满足最后 \\(2l\\) 个位置均为\')\'的方案数(考虑后 \\(2l\\) 个位置的匹配位置,将序列分成 \\(2l+1\\) 段)。可以使用反射法,方案数为 \\(\\binom2nn+l - \\binom2nn+l+1\\)。
考虑两棵虚树,它们的关键点个数、关键点深度和、边数分别为 \\((r,k,l)\\) 和 \\((r+1,k,l)\\),那么它们的贡献会抵消。
让我们重新列举一下合法虚树需要满足的条件:
- 结点无标号,但可能为“关键点”;
- 所有叶子必为“关键点”;
- 所有“关键点”的深度之和为 \\(n\\) \\((n\\ge 1)\\);
- 结点的儿子之间有先后顺序。
因为所有叶子都是关键点,所以在 DFS 的过程中,如果出现入栈之后立即出栈的情况,则一定访问到了关键点。
我们可以按 DFS 中的出栈顺序给“关键点”标上 \\(1..k\\) 的编号。
设在“关键点” \\(i\\) 出栈前,入栈、出栈操作分别进行了 \\(a_i,b_i\\) 次。可以观察到下列性质:
- \\(\\sum_i=1^k b_i-a_i = n\\);
- \\(1\\le a_1\\le a_2\\le \\cdots\\le a_k\\);
- \\(0= b_1 < b_2 < \\cdots < b_k\\);
- \\(b_i<a_i\\) \\((\\forall 1\\le i\\le k)\\);
- \\(b_i+1\\le a_i\\) \\((\\forall 1\\le i \\le k)\\);
- 树的边数是 \\(a_k\\);
- 合法的序列 \\((a_1,b_1), (a_2,b_2), \\cdots, (a_k,b_k)\\) 与合法的树构成双射。
为了方便表示,我们把合法序列画成方格图:假设有一个向右、向上无限延伸的方格图,我们只保留最下面的 \\(k\\) 行,对于从下往上的第 \\(i\\) 行,我们只保留第 \\(b_i+1\\) 到第 \\(a_i+1\\) 个格子。这样,画出的方格图是联通的。
为了体现 \\(b_k<a_k\\) 这条性质,我们在方格图第 \\(k\\) 行第 \\(a_k+1\\) 个格子上方添加一个格子。
考虑按照下图中的方法构造对合:
这样,在大部分情况中,我们总能把合法的方格图完美匹配,每对匹配的宽度相同、高度差 \\(1\\),这使得它们在答案的式子中抵消了。所有不能被匹配的方格图都属于下面这种情况:
因此,原答案和只保留这种情况的答案是一样的。答案为:
也可以写成:
2019.8.31 互不侵犯
题目描述
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
注:数据有加强(2018/4/25)
输入格式
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
输出格式
所得的方案数
输入输出样例
3 2
16
题目来源洛谷P1896/四川省选
有点像八皇后 但是看数据范围应该可以用状压dp
上代码
#include<iostream> #include<cstdio> using namespace std; long long n,k,dp[15][2050][205],sc[2050],num[2050]; long long ans,cnt; long long getnum(long long x) long long res=0; while(x)res+=(x&1),x>>=1; return num[(int)cnt]=res; int main() scanf("%lld%lld",&n,&k); long long maxn=(1<<n)-1; for(long long i=0;i<=maxn;i++) if(!(i&(i<<1)))sc[++cnt]=i,dp[1][cnt][getnum(i)]=1; for(long long i=2;i<=n;i++) for(long long j=1;j<=cnt;j++) for(long long l=1;l<=cnt;l++) long long x=sc[j],y=sc[l]; if(x&y)continue; if(x&(y<<1))continue; if(x&(y>>1))continue; for(long long m=0;m<=k;m++)dp[i][j][m+num[j]]+=dp[i-1][l][m]; for(long long i=1;i<=cnt;i++)ans+=dp[n][i][k]; printf("%lld",ans); return 0;
以上是关于数轴上连 n 条弦,共有 k 个交点的方案数的主要内容,如果未能解决你的问题,请参考以下文章