洛谷P1976 鸡蛋饼

题目链接点这里

题目背景

Czyzoiers 都想知道小 x 为什么对鸡蛋饼情有独钟。经过一番逼问,小 x 道出了实情:因为他喜欢圆。

题目描述

最近小 x 又发现了一个关于圆的有趣的问题:在圆上有 2N 个不同的点,小 x 想用 N 条线段把这些点连接起来(每个点只能连一条线段), 使所有的线段都不相交,他想知道这样的连接方案有多少种?

输入格式

有且仅有一个正整数 N 。 (N2999)

输出格式

要求的方案数(结果 mod100000007)。

输入输出样例

输入 #1
24
输出 #1
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
",f[n*2]);//一定要知道,答案是n*2! 
15     return 0;
16 }

题目到此结束!

原文地址:https://www.cnblogs.com/xinxiyuan/p/11348822.html