QQ联系我

BZOJ 1002: [FJOI2007]轮状病毒

1002: [FJOI2007]轮状病毒

Time Limit: 1 Sec  Memory Limit: 162 MB

Submit: 5785  Solved: 3140

[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

题解

最小生成树计数,用基尔霍夫矩阵可以推出递推式f[i]=f[i-1]*3-f[i-2]+2(太弱了推不来),注意要用高精度。

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=105;
int n;
struct num{
	int len;
	int a[105];
	num(){
		memset(a,0,sizeof(a));
	}
	num operator *(int b){
		num c;
		c.len=len;
		for(int i=1;i<=len+1;i++){
			c.a[i]=a[i]*b;
			c.a[i]+=c.a[i-1]/10;
			c.a[i-1]%=10;
		}
		if(c.a[len+1])c.len++;
		return c;
	}
	num operator -(num b){
		num c;
		c.len=len;
		for(int i=1;i<=len;i++){
			c.a[i]+=a[i]-b.a[i];
			if(c.a[i]<0){
				c.a[i]+=10;
				c.a[i+1]--;
			}
		}
		if(c.a[len]==0)c.len--;
		return c;
	}
	num operator +(int b){
		num c;
		c.len=len;
		c.a[1]+=b;
		for(int i=1;i<=len;i++){
			c.a[i]+=a[i];
			c.a[i+1]=c.a[i]/10;
			c.a[i]%=10;
		}
		if(c.a[len+1])c.len++;
		return c;
	}
	num operator =(num b){
		for(int i=1;i<=b.len;i++)a[i]=b.a[i];
		len=b.len;
		return *this;
	}
}f[N];
int main(){
	f[1].a[1]=1,f[2].a[1]=5;
	f[1].len=f[2].len=1;
	scanf("%d",&n);
	for(int i=3;i<=n;i++){
		f[i]=f[i-1]*3-f[i-2]+2;
	}
	for(int i=f[n].len;i>=1;i--){
		printf("%d",f[n].a[i]);
	}
	printf("\n");
	return 0;
}
posted @ 2017-10-12 18:09  czy020202  阅读(113)  评论(0编辑  收藏  举报