HDOJ2065 “红色病毒”问题

来源:互联网 发布:易语言access sql查询 编辑:程序博客网 时间:2024/05/17 09:10

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2065


直接求出组合公式很难,表示数学不好,所以只能在f(n-1)和f(n)之间找关系了。

长度为n-1个字符的所有排列可以分成四种,即A出现偶数次、C出现偶数次,A出现偶数次、C出现奇数次,

A出现奇数次、C出现偶数次,A出现奇数次、C出现奇数次。

我们用下列方式表示每种情况出现的次数

f(n-1)(A0C0) ;A出现偶数次,C出现偶数次

f(n-1)(A0C1) ;

f(n-1)(A1C0) ;

f(n-1)(A1C1) ;

。现在我们考虑长度为n个字符的情况

f(n)(A0C0) = 2*f(n-1)(A0C0)+f(n-1)(A1C0)+f(n-1)(A0C0); 

2*f(n-1)(A0C0);表示在n-1个字符出现A出现偶数次C出现偶数次的时候,我们可以添加一个字符B或D使得

长度为n时,A出现的次数为偶数次,C出现的次数也为偶数次。

使得n-1个字符,添加一个字符后,A出现的次数为偶数次,C出现的次数为偶数次,还有两种情况,

就是原来A出现奇数次C出现偶数次,再添加一个A,原来A出现偶数次,C出现奇数次,再添加一个C

所以f(n)(A0C0) =  2*f(n-1)(A0C0)+f(n-1)(A1C0)+f(n-1)(A0C0);

 

f(n)(A0C1) ;

f(n)(A1C0) ;

f(n)(A1C1) ;可由上面的方法推得。


题目中,n值可能很大。所以不能对每次的输入都求一边,我们可以先打表。

因为保存的是后两位。结果只有100种,还有f(n)总是由三个f(n-1)相加而得,所以

打表100,000之后肯定会重复。

打表发现n=11之后开始出现循环,n=11和n=31,51,71,的结果相同。

所以只需求出a[1-31]就行了。

由于数学不太好,没有在公式中得到这个规律。


   //code

#include <iostream>#include <fstream>using namespace std;#define MAX 32int res[MAX];void init(){int a,b,c,d;a = 2;//A0C0b = 1;//A0C1c = 1;//A1C0d = 0;//A1C1res[1]=a;int tmpa,tmpb,tmpc,tmpd;for (__int64 i=2;i<MAX;++i){tmpa = a;tmpb = b; tmpc = c; tmpd = d;a = ((tmpa<<1) + tmpb + tmpc)%100;b = (tmpa + (tmpb<<1) + tmpd)%100;c = ((tmpc<<1) + tmpa + tmpd)%100;d = ((tmpd<<1) + tmpc + tmpb)%100;res[i] = a;}}int main(){int t;int a,b,c,d;int firstGroup=1;int test=1;int test2 = 1;init();while(1){cin>>t;if(t==0)break;int count=1;while(t--){a = 2;//A0C0b = 1;//A0C1c = 1;//A1C0d = 0;//A1C1__int64 n;cin>>n;if(n>=1 && n<=10)a = res[n];else{n = n%20;if(n<11)n = n+20;a = res[n];}cout<<"Case "<<count++<<": "<<res[n]<<endl;}cout<<endl;}return 0;}


  



原创粉丝点击