bzoj1002:[FJOI2007]轮状病毒

思路:一道很裸的生成树计数问题,然而要高精度,而且听说直接行列式求值会被卡精度,所以可以模拟行列式求值的过程得到递推公式:f[i]=3*f[i-1]-f[i-2]+2,证明详见vfk博客:

http://vfleaking.blog.163.com/blog/static/17480763420119685112649/

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn 105
#define mod 100000000

int n;

struct bignum{
	int len;
	int a[maxn*10];
	bool operator <(const bignum &b)const{
		if (len!=b.len) return len<b.len;
		for (int i=len;i;i--) if (a[i]<b.a[i]) return 1;
		return 0;
	}
	bignum operator +(const bignum &b){
		bignum c;c.len=max(len,b.len);memset(c.a,0,sizeof(c.a));
		for (int i=1;i<=c.len;i++){
			c.a[i]+=a[i]+b.a[i];
			if (c.a[i]>mod) c.a[i+1]=c.a[i]/mod,c.a[i]%=mod;
		}
		if (c.a[c.len+1]) c.len++;
		return c;
	}
	bignum operator -(const bignum &b){
		bignum c;c.len=max(len,b.len);memset(c.a,0,sizeof(c.a));
		for (int i=1;i<=c.len;i++){
			c.a[i]=a[i]-b.a[i];
			if (c.a[i]<0) c.a[i]+=mod,a[i+1]--;
		}
		for (;!c.a[c.len]&&c.len>1;c.len--);
		return c;
	}
	void initialize(char *s){
		int l=strlen(s+1);
		for (int i=l;i>=1;i-=8){
			len++;int x=pow(10,min(i-1,7)),t=max(i-8+1,1);
			while (x) a[len]+=(s[t]-'0')*x,t++,x/=10;
		}
	}
	void print(){
		printf("%d",a[len]);
		for (int i=len-1;i;i--) printf("%08d",a[i]);
	}
}f[maxn],t;

int main(){
	scanf("%d",&n);f[1].a[1]=1,f[1].len=1,f[2].a[1]=5,f[2].len=1,t.a[1]=2,t.len=1;
	for (int i=3;i<=n;i++) f[i]=f[i-1]+f[i-1]+f[i-1]-f[i-2]+t;
	f[n].print();
	return 0;
}

 

posted @ 2016-10-30 20:40  DUXT  阅读(145)  评论(0编辑  收藏  举报