1002: [FJOI2007]轮状病毒

Description

  轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的。一个N轮状基由圆环上N个不同的基原子
和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道。如下图所示

  N轮状病毒的产生规律是在一个N轮状基中删去若干条边,使得各原子之间有唯一的信息通道,例如共有16个不
同的3轮状病毒,如下图所示

  现给定n(N<=100),编程计算有多少个不同的n轮状病毒

 

Input

  第一行有1个正整数n

Output

  计算出的不同的n轮状病毒数输出

Sample Input

3

Sample Output

16
 
//一开始非常nb地推了个组合数的公式,但是要写高精阶乘 高精除高精,就没写
//然后就写longlong看看能过几个点
//A掉一个点,和题解对了下,发现只有n<=3的时候是对的 

//不会别的做法,看了题解。
//有矩阵树定理的做法和递推的做法
//感觉递推的比较好写,不用写高精乘法
//将n<=5的ans写出来,可以发现f[n]=3*f[n-1]-f[n-2]+2
//其实上面那个式子是个斐波那契的变形,整理一下可以得到这个式子 

//不可避免地要写高精 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int n;
int ans[105][1005];
int len[105];
int mul[1005];

void calc(int x)
{
    int m=x-2,n=x-1;
    int cnt=0;int l=len[n];
    for(int i=1;i<=l;++i)
    {
        mul[i]=(3*ans[n][i]+cnt)%10;
        cnt=(3*ans[n][i]+cnt)/10;
    }
    if(cnt)
        mul[++l]=cnt;
    cnt=2;
    for(int i=1;i<=l;++i)
    {
        ans[x][i]=(mul[i]-ans[m][i]+cnt+10)%10;
        if(mul[i]-ans[m][i]+cnt<0)
            cnt=-1;
        else
            cnt=(mul[i]-ans[m][i]+cnt)/10;
    }
    if(cnt)
        ans[x][l+1]=cnt,len[x]=l+1;
    else
        len[x]=l;
    return;
}

int main()
{
    scanf("%d",&n);
    ans[1][1]=1,len[1]=1;
    ans[2][1]=5,len[2]=1;
    for(int i=3;i<=n;++i)
        calc(i);
    for(int i=len[n];i;--i)
        cout<<ans[n][i];
    return 0;
}

 

posted @ 2018-09-12 11:25  whymhe  阅读(127)  评论(0编辑  收藏  举报