洛谷P2144 [FJOI2007]轮状病毒

题目描述

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

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

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

这里写图片描述

输入输出格式

输入格式:
第一行有1个正整数n。

输出格式:
将编程计算出的不同的n轮状病毒数输出

输入输出样例

输入样例#1:
3
输出样例#1:
16

【题解】

做这题颇有感触啊,感觉省选题目画半个小时画图不吃亏。

看到题目,反正我的第一反应是递推。递推就要有递推式,于是我花了将近20分钟,画出n=1~5情况的轮状病毒个数:

1 5 16 45 121……

乍一看,奇数项是完全平方数,偶数项是5的倍数,我想的是往平方数上靠,于是转化成了这样:

1*1 3*3-4 4*4 7*7-4 11*11……

1 3 4 7 11……

就是这样,原来是个变形的Fibonacci数列,前两项为1和3,然后对每一项平方,如果是偶数项就减4,AC~

递推式:F[n]=f[n]f[n]-4(n+1 mod 2),f[n]=f[n-1]+f[n-2],f[1]=1,f[2]=3

然后难点就在于高精度了。(这玩意我搞了一个半小时。。。)

对于高精度,我喜欢用刘汝佳《算法竞赛入门经典》上的大整数类,这种方法就是定义一个class,通过符号重载,让打高精度运算和打普通运算一样简单。这样就不用专为每道题打专门的高精度,需要时在程序前套板子即可。(但这样似乎加大了代码量)

随代码附上高精度模板:

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define fp(i,a,b) for(int i=a;i<=b;i++)
#define fq(i,a,b) for(int i=a;i>=b;i--)
#define il inline
#define re register
#define ll long long 
using namespace std;
const int maxN=100001;
const int inf=2147483647;
class BigInteger { public:

int size,num[1000];//size代表数的长度,num存大整型数

    BigInteger()//定义时自动清零
        {
            size=0;
            memset(num,0,sizeof(num));
        }
    BigInteger(int data)
        {
            size=0;
            while (data!=0)
            {
                size++;
                num[size]=data%10;
                data=data/10;
            }
        }
    void init(int data)//用来给大整型变量赋整型值
        {
            size=0;
            while (data!=0)
            {
                size++;
                num[size]=data%10;
                data=data/10;
            }
        }
};
BigInteger operator + (BigInteger A,BigInteger B)//高精度加法
{
    BigInteger Ans;
    int s=max(A.size,B.size);
    Ans.size=s;
    for (int i=1;i<=s;i++)
        Ans.num[i]=A.num[i]+B.num[i];
    for (int i=1;i<=s;i++)
        if (Ans.num[i]>=10)
        {
            Ans.num[i+1]+=Ans.num[i]/10;
            Ans.num[i]=Ans.num[i]%10;
        }
    if (Ans.num[s+1]!=0)
        Ans.size++;
    return Ans;
}
BigInteger operator - (BigInteger A,BigInteger B)//高精度减法
{
    BigInteger Ans;
    int s=max(A.size,B.size);
    Ans.size=s;
    for (int i=1;i<=s;i++)
        Ans.num[i]=A.num[i]-B.num[i];
    for (int i=1;i<=s;i++)
        if (Ans.num[i]<0)
        {
            Ans.num[i+1]-=Ans.num[i]/10;
            Ans.num[i]=Ans.num[i]%10;
        }
    if (Ans.num[s+1]!=0)
        Ans.size++;
    return Ans;
}
ostream & operator << (ostream &os,BigInteger A)//用于大整型数的输出(只能用cout)
{
    int s=A.size;
    for (int i=s;i>=1;i--)
        os<<A.num[i];
    return os;
}
BigInteger operator * (BigInteger A,BigInteger B)//高精度乘法
{
    BigInteger Ans;
    int s1=A.size,s2=B.size;
    for (int i=1;i<=s1;i++)
        for (int j=1;j<=s2;j++)
            Ans.num[i+j-1]+=A.num[i]*B.num[j];
    int s=s1+s2-1;
    int k=1;
    while ((Ans.num[k]!=0)||(k<=s))
    {
        Ans.num[k+1]+=Ans.num[k]/10;
        Ans.num[k]=Ans.num[k]%10;
        k++;
    }
    if (Ans.num[k]==0)
        k--;
    Ans.size=k;
    return Ans;
}
BigInteger Ans,Ans1,Ans2;//定义大整型数
il int gi()
{
   int x=0;
   short int t=1;
   char ch=getchar();
  while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
  if(ch=='-') t=-1,ch=getchar();
  while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  return x*t;
}
int main()
{
    Ans1.init(1);//把Ans1赋值为1,不能写Ans1=1!!!
    Ans2.init(3);//把Ans2赋值为3,不能写Ans2=3!!!
    int n=gi();
    for(int i=3;i<=n;i++) if(i%2) Ans1=Ans1+Ans2;
        else Ans2=Ans2+Ans1;
    if(n%2) Ans=Ans1;
    else Ans=Ans2;//求f[n]
    if(n%2) Ans=Ans*Ans;
    else Ans=Ans*Ans-4;//求F[n]
    cout<<Ans<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值