(题目链接点这里)
题目背景
Czyzoiers 都想知道小 x 为什么对鸡蛋饼情有独钟。经过一番逼问,小 x 道出了实情:因为他喜欢圆。
题目描述
最近小 x 又发现了一个关于圆的有趣的问题:在圆上有 2N 个不同的点,小 x 想用 N 条线段把这些点连接起来(每个点只能连一条线段), 使所有的线段都不相交,他想知道这样的连接方案有多少种?
输入格式
有且仅有一个正整数 N 。 (N≤2999)
输出格式
要求的方案数(结果 mod100000007)。
输入输出样例
24
4057031
题解:
这一题是一道非常简洁明了的漂亮的递推题。(本人认为)
首先我们知道,对于题目中圆上的任意一点,有且仅有一个点与之连线。
而又因为任意两条连线不能相交,所以就相当于一条直线把圆周划分成了两部分,我们设为A和B。
所以A部分的点不能与B部分的点相连。
正是因为这样,我们就可以将一个大圆周切成两个小圆周进行处理。
(是不是听起来或者看起来很像分治?对,没错!)
于是,问题就迎刃而解了!
我们设f[i]为圆上有i个点时的答案,随便找一点,枚举与它连线的i,得出递推方程式如下:
其中,f[2j-2]*f[i-2j]就相当于两边的方案数之积(搭配原理),而i%2==0是因为只有点的个数为偶数时,这些点才能两两匹配。
看到上面那两个递推方程式,你们可能会想:为什么f[0]=1呢?
那是因为:你被迫不连也是一种方案呀!(主动不连当然不符合要求)
现在你懂了吗?
如果还是没有,那就看代码吧!
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n; 4 long long f[6001]={1,0,1};//初始化,因为100000007*3000个数会爆int,所以开long long 5 int main() 6 { 7 cin>>n; 8 for(int i=4;i<=n*2;i+=2) 9 { 10 for(int j=2;j<=i;j+=2) 11 f[i]+=f[j-2]*f[i-j];//递推式 12 f[i]%=100000007; 13 } 14 printf("%d\n",f[n*2]);//一定要知道,答案是n*2! 15 return 0; 16 }
题目到此结束!