题目描述
轮状病毒有很多变种。许多轮状病毒都是由一个轮状基产生。一个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;
}