BZOJ1002: [FJOI2007]輪狀病毒
阿新 • • 發佈:2018-01-21
多少 註意 () esp 當前 ++ 信息 輸出 logs
2-1|1|0|0|
| f(3)|32-1|1|1|0|
| f(4)|42-1|1|1|1|
|ANS(4)(求和)|4^2|3|2|1|
bzoj 1002
Description
輪狀病毒有很多變種,所有輪狀病毒的變種都是從一個輪狀基產生的。一個N輪狀基由圓環上N個不同的基原子和圓心處一個核原子構成的,2個原子之間的邊表示這2個原子之間的信息通道。如下圖所示
N輪狀病毒的產生規律是在一個N輪狀基中刪去若幹條邊,使得各原子之間有唯一的信息通道,例如共有16個不同的3輪狀病毒,如下圖所示
現給定n(N<=100),編程計算有多少個不同的n輪狀病毒
Input
第一行有1個正整數n
Output
計算出的不同的n輪狀病毒數輸出
Sample Input
3
Sample Output
16
solve
我們只要選擇連在一起有幾個就行了,相當於把n分成很多段連續的圓弧
可以由遞推關系來解決
以下面n=4為例
上圖為一種可行解,弧上的實、虛線可互相替換,十字上的實、虛線可互相替換
有4*4種方法
上圖,弧上n=3的點集再連上4的,有1*f(3)種的情況
上圖,相連的是同一點集,顯然有2*f(2)種
同理,還有3*f(1)種
於是,有了f(4)=4*4+1*f(3)+2*f(2)+3*f(1)
同樣的
f(i)=ii+1f(i-1)+2f(i-2)+3f(i-3)+...+(n-1)*f(1)
這時再將上式改為遞推式
f(i)=2*i-1 + f(1) + f(2) + ... + f(i-1) + f(i-1)
怎麽來的呢?
還以n=4為例
| 當前式 | 常數| f(1)| f(2)| f(3)|
|:-------:|:--------:|:--------:|:---------:|:---------:|
| f(1)| 12-1| 0 | 0 | 0 |
| f(2)|2
| f(3)|32-1|1|1|0|
| f(4)|42-1|1|1|1|
|ANS(4)(求和)|4^2|3|2|1|
然後就可以搞事情了,遞推式推到底就AC了
註意高精
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 1000
using namespace std;
int n;
struct BIGNUM{
int num[MAXN];
int len;
BIGNUM(){
memset(num,0,sizeof(num));
len=1 ;
}
}SUM,f,ANS;
BIGNUM ADD(const BIGNUM &x,const BIGNUM &y){
int len=max(x.len,y.len);
int i;
BIGNUM tmp;
for(i=0;i<=len;i++){
tmp.num[i]+=x.num[i]+y.num[i];
tmp.num[i+1]=tmp.num[i]/10;
tmp.num[i]%=10;
}
if(tmp.num[len])
len++;
tmp.len=len;
return tmp;
}
void PRINT(const BIGNUM & x){
int i;
for(i=x.len-1;i>=0;i--)
printf("%d",x.num[i]);
}
void solve(){
int i;
for(i=1;i<=n;i++){
f.num[0]+=i*2-1;
f=ADD(f,SUM);
SUM=ADD(f,SUM);
ANS=f;
}
}
int main(){
scanf("%d",&n);
solve();
PRINT(ANS);
return 0;
}
BZOJ1002: [FJOI2007]輪狀病毒