• [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();
    }
  • 相关阅读:
    参数迭代的初始值
    印刷体、手写体公式图片OCR识别转latex
    混合型变量聚类的观点
    算法优化大概的方法
    梯度下降法
    支持向量机-可分的类
    LaTex希腊字母
    红黑树删除操作
    红黑树插入操作
    红黑树
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/7421827.html
Copyright © 2020-2023  润新知