2014ACM广州赛区现场赛J题题解.

Yue Fei is one of the most famous military general in Chinese history.He led Southern Song army in the wars against the Jin dynasty of northern China. Yue Fei achieved a lot of victory and hopefully could retake Kaifeng ,the former capital of Song occupied by Jin. Fearing that retaking Kaifeng might cause the Jin to release former Emperor Song Qinzong, threatening his throne, Emperor Song Gaozong took some corrupted officers' advice, sending 12 urgent orders in the form of 12 gold plaques to Yue Fei, recalling him back to the capital.

Then Yue Fei was put into prison and was killed under a charge of "maybe there is" treason. But later Yue Fei was posthumously pardoned and rehabilitated, and became a symbol of loyalty to the country. The four corrupted officers who set him up were Qin Hui,Qin Hui's wife Lady Wang, Moqi Xie and Zhang Jun. People made kneeling iron statues of them and put the statues before Yue Fei's tomb (located by the West Lake, Hangzhou). For centuries, these statues have been cursed, spat and urinated upon by people. (Now please don't do that if you go to Hangzhou and see the statues.)

One of the most important battle Yue Fei won is the battle in Zhuxian town. In Zhuxian town, Yue Fei wanted to deploy some barracks, and connected those barracks with roads. Yue Fei needed all the barracks to be connected, and in order to save money, he wanted to build as less roads as possible. There couldn't be a barrack which is too important, or else it would be attacked by enemies. So Yue Fei required that NO barrack could connect with more than 3 roads. According to his battle theory, Yue Fei also required that the length of the longest route among the barracks is exactly K. Note that the length of a route is defined as the number of barracks lied on it and there may be several longest routes with the same length K.

Yue Fei wanted to know, in how many different ways could he deploy the barracks and roads. All barracks could be considered as no different. Yue Fei could deploy as many barracks as he wanted.

For example, if K is 3,Yue Fei had 2 ways to deploy the barracks and roads as shown in figure1. If K is 4, the 3 kinds of layouts is shown in figure 2. (Thick dots stand for barracks, and segments stand for roads):


Please bring your computer and go back to Yue Fei's time to help him so that you may change the history.

Input

The input consists of no more than 25 test cases.

For each test, there is only one line containing a integer K(1<=K<=100,000)denoting the length of the longest route.

The input ends by K=0.

Output

For each test case,print an integer denoting the number if different ways modulo 1^9+7.

Sample Input

3

4

0

Sample Output

2

3

传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5136

题目大意:给你一个k,然后让你求满足条件的树形结构,条件1:树的最长链上的节点数等于k;条件2:每个节点的度最大为3。

题目分析:不管你怎么想的反正我的第一感觉就是‘同分异构体(其实也只是有点像)’?然后就去找规律,找着找着发现重复的情况太多了不知道怎么去重。第二感觉,递推?感觉K是能一层层推上去的,然后推着推着发现,还是有太多的重复情况(因为你按规律建的一个结构可能换一条链来看的话就很有可能与之前构造的相同)。最后终于找到正确姿势!当遇到这种情况多,重的很多的情况时,可以先固定一些已知条件,比如说此题的最长链长度为K。假设我们已经固定了最长链,关键是怎么固定呢?中点!无论是怎么样的链它都得有个中点,在数最长链是都得过这个中点!所以我们很容易就将K分奇偶来讨论,当K为奇数,最长链中间是一个点(这个点能连3条边);当K为偶数,最长链中间是一条线段,我们可以在这条线段中间加一个点(空点,并且它只能连两条边)。让我们想象一下,我们用手拿着这个点提起整个树形结构时,我们会发现整个变成了个二叉树!然后我们只要先预处理出深度为K/2的不一样的二叉树有多少种,再用组合数学就可以将所有的情况都算出来了~

PS:如果你有什么其他的方法或思路,欢迎再下面留言告诉我~还有就是我代码实现的有点丑~ ~ 如果你认为我的代码哪里还能改的更漂亮或者程序更优也请留言告诉我~

#include<cmath>
#include<cstdio>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=(1<<31)-10;
const int MOD=(1e9)+7;
long long dp[100100],sige[100100];
int main()
{
    int i,k;
    long long ans,two,c2,c3,dp0,dp1,dp2;
    dp[1]=1;sige[0]=0;sige[1]=1;///预处理出二叉树个数。
    for (i=2;i<100010;i++) {
        dp[i]=(dp[i-1]*(sige[i-2]+1))%MOD;
        dp[i]=(dp[i]+dp[i-1]*(dp[i-1]-1)/2)%MOD;
        dp[i]=(dp[i]+dp[i-1])%MOD;
        sige[i]=(sige[i-1]+dp[i])%MOD;
    }
    while (scanf("%d", &k)&&k) {
        if (k==1) {
            printf("1\n");continue;
        }
        if (k&1) {///奇数情况。
            two=ans=(dp[k/2]*(dp[k/2]-1)/2+dp[k/2])%MOD;///中间点只连2个二叉子树(包括两个相同的情况)。
            ans=(ans+two*sige[k/2-1])%MOD;///中间点连上第三个点,并且第三个子树深度不等于k/2;
            ans=(ans+dp[k/2]*(dp[k/2]-1))%MOD;///中间点连的3个子树深度都为k/2。并且有两颗相同。
            ans=(ans+dp[k/2])%MOD;///中间点连的3个子树深度都为k/2。并且3颗都相同。
            dp0=dp[k/2];dp1=dp[k/2]-1;dp2=dp[k/2]-2;c2=1;c3=1;
             ///C[dp[k/2],3],3颗子树深度都为k/2,并且都不相同。防爆long long。~ ~    这处理得好丑~
            if (c2&&dp0%2==0) {
                dp0=dp0/2;c2=0;
            }
            if (c2&&dp1%2==0) {
                dp1=dp1/2;c2=0;
            }
            if (c2&&dp2%2==0) {
                dp2=dp2/2;c2=0;
            }
            if (c3&&dp0%3==0) {
                dp0=dp0/3;c3=0;
            }
            if (c3&&dp1%3==0) {
                dp1=dp1/3;c3=0;
            }
            if (c3&&dp2%3==0) {
                dp2=dp2/3;c3=0;
            }
            ans=(ans+(((dp0*dp1)%MOD)*dp2)%MOD)%MOD;///先处理掉/6取余的问题!!!
            printf("%d\n", ans);
        } else {///偶数情况。
            ans=(dp[k/2]*(dp[k/2]-1)/2)%MOD;///不重样的深度为k/2的子树的组合。
            ans=(ans+dp[k/2])%MOD;///加上两颗子树相同的情况。
            printf("%d\n", ans);
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值