[FJOI2007]轮状病毒

1002: [FJOI2007]轮状病毒

Time Limit: 1 Sec  Memory Limit: 162 MB
[Submit][Status][Discuss]

Description

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

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

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

Input

  第一行有1个正整数n

Output

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

Sample Input

3

Sample Output

16
 

每种n轮状病毒对应着一种不同的生成树

同样,n+1个点的生成树对应着不同的n轮状病毒

所以 n轮状病毒的种数 ==

n+1个点,已知每个点可以连出的边 的生成树的个数

现在问题转化为求生成树的个数

矩阵树定理即可

但是不写高精只能做到50分

然后你可以根据这个打表找出规律(我没找出来)

f[i]=3*f[i-1]-f[i-2]+2

再写个高精就A了

矩阵树定理打表代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
int C[101][101];
int n;
void Matrix_tree()
{
    memset(C,0,sizeof(C));
    if(n==1)
    {
        C[0][0]=C[1][1]=1;
        C[0][1]=C[1][0]=1;
    }
    else if(n==2)
    {
        C[0][0]=2;
        C[1][1]=C[2][2]=3;
        C[0][1]=C[0][2]=C[1][0]=C[2][0]=1;
        C[1][2]=C[2][1]=2;
    }
    else
    {
        C[0][0]=n;
        for(int i=1;i<=n;i++) C[i][0]=C[0][i]=1;
        for(int i=1;i<=n;i++) C[i][i]=3;
        C[1][2]=C[1][n]=1;
        C[n][n-1]=C[n][1]=1;
        for(int i=1;i<n;i++) C[i][i-1]=C[i][i+1]=1;
    }
    LL ans=1,t;
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
            while(C[j][i])
            {
                t=C[i][i]/C[j][i];
                for(int k=i;k<=n;k++) C[i][k]-=C[j][k]*t;
                for(int k=i;k<=n;k++) swap(C[i][k],C[j][k]);
                ans=-1;
            }
        ans*=C[i][i];
    }
    if(ans<0) ans=-ans;
    cout<<ans<<endl;
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    Matrix_tree();
}

AC代码

#include<cstdio>
#include<cstring>
using namespace std;
struct node
{
    int len;
    int num[1001];
    node() { len=0; memset(num,0,sizeof(num)); } 
    node operator * (int p) const
    {
        node a;
        for(int i=1;i<=len;i++) 
        a.num[i]=num[i]*p;
        for(int i=1;i<=len;i++) a.num[i+1]+=a.num[i]/10,a.num[i]%=10;
        a.len=len;
        while(a.num[a.len+1]) a.len++;
        return a; 
    }
    node operator - (node p)
    {
        node a;
        for(int i=1;i<=len;i++) a.num[i]=num[i];
        for(int i=1;i<=len;i++) 
        {
            if(a.num[i]<p.num[i]) a.num[i]+=10,a.num[i+1]--;
            a.num[i]=a.num[i]-p.num[i];
        }
        a.len=len;
        while(len && !a.num[a.len]) len--;
        return a;
    }
    node operator + (int p)
    {
        node a;
        a.num[1]=num[1]+2;
        for(int i=2;i<=len;i++) a.num[i]=num[i];
        for(int i=1;i<=len;i++)
            if(a.num[i]>=10) a.num[i+1]++,a.num[i]-=10;
        a.len=len;
        if(a.num[len+1]) a.len++;
        return a;
    }
    void operator = (node p)
    {
        this->len=p.len;
        for(int i=1;i<=p.len;i++) this->num[i]=p.num[i];
    } 
    void print()
    {
        for(int i=len;i;i--) printf("%d",num[i]);
    }
};
node f[101];
int main()
{
    int n;
    scanf("%d",&n);
    f[1].len=f[2].len=1;
    f[1].num[1]=1; f[2].num[1]=5;
    for(int i=3;i<=n;i++) f[i]=f[i-1]*3-f[i-2]+2;
    f[n].print();
}
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7421827.html