bzoj1002:[FJOI2007]轮状病毒

时间:2023-03-09 00:41:25
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;
}