HDU 2065 "红色病毒"问题 【附递推】

来源:互联网 发布:三生网络直销罗奇 编辑:程序博客网 时间:2024/05/17 03:37
Problem Description
医学界发现的新病毒因其蔓延速度和Internet上传播的"红色病毒"不相上下,被称为"红色病毒",经研究发现,该病毒及其变种的DNA的一条单链中,胞嘧啶,腺嘧啶均是成对出现的。
现在有一长度为N的字符串,满足一下条件:
(1) 字符串仅由A,B,C,D四个字母组成;
(2) A出现偶数次(也可以不出现);
(3) C出现偶数次(也可以不出现);
计算满足条件的字符串个数.
当N=2时,所有满足条件的字符串有如下6个:BB,BD,DB,DD,AA,CC.
由于这个数据肯能非常庞大,你只要给出最后两位数字即可.
 

Input
每组输入的第一行是一个整数T,表示测试实例的个数,下面是T行数据,每行一个整数N(1<=N<2^64),当T=0时结束.
 

Output
对于每个测试实例,输出字符串个数的最后两位,每组输出后跟一个空行.
 

Sample Input
41420113142460
 

Sample Output
Case 1: 2Case 2: 72Case 3: 32Case 4: 0Case 1: 56Case 2: 72Case 3: 56
 

由于B、D可出现0-n之间任意次,A、C只能出现0-n之间偶数次,
结合指数型母函数可得:
f(x)=(1+x/1!+x^2/2!+x^3/3!…+x^n/n!)^2*(1+x^2/2!+x^4/4!+x^6/6!…+…)^2
由泰勒公式:
  e^x=1+x/1!+x^2/2!+x^3/3!…+x^n/n!;
e^(-x)=1-x/1!+x^2/2!-x^3/3!+…-…
两式相加可得:
e^x+e^(-x)=(1+x^2/2!+x^4/4!+x^6/6!…+…)*2;
所以:
f(x) =e^(2x) * ((e^x+e^(-x))/2)^2
  = (1/4) * e^(2x) * (e^(2x) + 2 + e^(-2x))
  = (1/4) * (e^(4x) + 2*e^(2x) +1)
     = (1/4) * ( (1+4x/1!+(4x)^2/2!+(4x)^3/3!+…+(4x)^n/n!) + 2*(1+2x/1!+(2x)^2/2!+(2x)^3/3!+…+(2x)^n/n!) +1)

得:  x^n/n! 项系数
a(n)    = (1/4) * ((4x)^n/n! + 2*(2x)^n/n!)
 = (1/4) * ( 4^n*x^n/n! + 2^(n+1)*x^n/n!)
 = (4^(n-1) + 2^(n-1)) * x^n/n!
即所求 F(n) = (4^(n-1) + 2^(n-1)) % 100.


#include <stdio.h>int pow_mod(int a, long long b, int m)//a^b mod m{if (b == 0) return 1;int x = pow_mod(a, b / 2, m);long long ans = (long long)x*x % m;if(b % 2 == 1) ans = ans*a%m;return (int)(ans);}int main(){int t,z;long long n;while (~scanf("%d", &t) && t) {int count = 0;while (t--) {scanf("%I64d", &n);z = (pow_mod(4, n - 1, 100) + pow_mod(2, n - 1, 100)) % 100;printf("Case %d: %d\n", ++count, z);}printf("\n");}return 0;}


递推法:
考虑n个字母时所有可能情况:【注意只考虑各字母出现次数不考虑排列】
f(n) =f(n,AOCO)+f(n,A0CJ)+f(n,AJCO)+f(n,AJCJ)[O、J分别对应相应字母出现次数的奇偶性]
       =f(n,0)        +f(n,1)      +f(n,2)        +f(n,3)
则当n+1个字母时
f(n+1,AOCO)=[f(n,AOCO)+B/C]+[f(n,A0CJ)+C]+[f(n,AJCO)+A],即f(n+1,0)=f(n,0)*2+f(n,1)+f(n,2)
f(n+1,AOCJ)=[f(n,AOCO)+C]+[f(n,A0CJ)+B/C]+[f(n,AJCJ)+A],即f(n+1,1)=f(n,0)+f(n,1)*2+f(n,3)
f(n+1,AJCO)=[f(n,AOCO)+A]+[f(n,AJCO)+B/C]+[f(n,AJCJ)+C],即f(n+1,2)=f(n,0)+f(n,2)*2+f(n,3)
f(n+1,AJCJ)=[f(n,AOCJ)+A]+[f(n,AJCO)+C]+[f(n,AJCJ)+B/C],即f(n+1,3)=f(n,1)+f(n,2)+f(n,3)*2
且f(1,0)=2,f(1,1)=f(1,2)=1,f(1,3)=0;
验证: f(2,0)=2*2+1+1=6;
     f(2,1)=2+1*2+0=4;
f(2,2)=2+1*2+0=4;
f(2,3)=1+1+0*2=2;
结果正确。
#include <stdio.h>#define maxn 10000int a[maxn][4] = { {0,0,0,0} ,{2,1,1,0} };int main(){for (int i = 2;i < maxn;i++) {a[i][0] = (a[i - 1][0] * 2 + a[i - 1][1] + a[i - 1][2])%100;a[i][1] = (a[i - 1][0] + a[i - 1][1] * 2 + a[i - 1][3])%100;a[i][2] = (a[i - 1][0] + a[i - 1][2] * 2 + a[i - 1][3])%100;a[i][3] = (a[i - 1][1] + a[i - 1][2] + a[i - 1][3] * 2)%100;}/*由于n可取值太大,不可能直接a[n][0]a输出,所以需要找规律,可以显示着输出前50项结果for (int i = 1;i <= 50;i+=5)printf("%2d %2d %2d %2d %2d\n", a[i][0], a[i+1][0], a[i+2][0], a[i+3][0], a[i+4][0]);可知从第a[20][0]起是周期为20的输出。*/int t;long long n;while (~scanf("%d", &t) && t) {int count = 0;while (t--) {scanf("%I64d", &n);if(n>20) n = n % 20 + 20;printf("Case %d: %d\n", ++count, a[n][0]);}printf("\n");}return 0;}


0 0
原创粉丝点击