您的位置:首页 > 其它

[HDU 2065][dp]"红色病毒"问题

2017-08-19 22:58 441 查看

“红色病毒”问题

Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 7414 Accepted Submission(s): 3064

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

4

1

4

20

11

3

14

24

6

0

Sample Output

Case 1: 2

Case 2: 72

Case 3: 32

Case 4: 0

Case 1: 56

Case 2: 72

Case 3: 56

Author

Rabbit

Source

RPG专场练习赛

Recommend

lcy | We have carefully selected several similar problems for you: 2062 2069 2070 2073 2077

题解

这道题给我第一感觉就是dp,写题卡的过程中在网上找题解,没发现用dp写的。这里就贴一份吧。

首先我们把状态分一下:

一、A和C均为偶数,这就是要求的。

二、A为偶数、C为奇数。

三、A为偶数、C为奇数。

四、A为奇数、C为奇数。

下面直接用序号①②③④代替以上状态。

开一个dp数组,第一维记为串长,第二维则标记以上状态。

则①对应dp[i][0],②dp[i][1],③dp[i][2], ④dp[i][3]。

如dp[i][0]表示串长为i,A C数量均为偶数的数量。

初始状态dp[1][0] = 2, dp[1][1] = 1, dp[1][2] = 1, dp[1][3] = 0;

再推导递推式

串长为i的①串,可以由串长为i - 1的①串在后面添加 “B” 或 “D”, 或者串长为i - 1的②串+ “C”, 或串长为i - 1的③串 + “A”得到。

dp[i][0] = dp[i - 1][0] * 2 + dp[i - 1][1] + dp[i - 1][2];


串长为i的②串可以由串长为i-1的①串+ “C”,或②串 + “B” 或 “D”, 或④串 + “A”得到。

dp[i][1] = dp[i - 1][0]  + dp[i - 1][1] * 2 + dp[i - 1][3];


③串和②串相似

dp[i][2] = dp[i - 1][0]  + dp[i - 1][2] * 2 + dp[i - 1][3] ;


串长为i的④串可以由,串长为i - 1的②串 + “C” , ③串 + “A”,四串 + “B” 或 “D”。

dp[i][3] = dp[i - 1][1] + dp[i - 1][2] + dp[i - 1][3] * 2;


递推完成。不过本题还有一些小细节需要处理,题目要求的是末两位数字。如果直接在递推过程对100取模,会导致结果错误,我采取的做法是对推过程对10000取模,最后输出答案时再对100取模。

同时,由于n范围为2^64,直接递推到n肯定会超时。而最终答案只包含两位,所以其具有周期性是显而易见,打表出来,找下周期就可以解决了。

//#define LOCAL
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <iostream>
#include <cstdlib>
#include <algorithm>

using namespace std;

#define LL long long
#define ll long long
#define INF 0x3f3f3f3f
#define maxn MAX_N
#define MOD mod
#define MMT(x,i) memset(x,i,sizeof(x))
#define REP(i, n) for(int i = 0; i < n; i++)
#define FOR(i, n) for(int i = 1; i <= n; i++)
#define pb push_back
#define mp make_pair
#define X first
#define Y second

const LL MOD = 1e9 + 7;
const double pi = acos(-1.0);
const double E = exp(1);
const double EPS = 1e-8;

const int MAX_N = 1000010;
int dp[10010][4];
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
dp[0][0] = dp[0][1] = dp[0][2] = 1;
dp[1][0] = 2, dp[1][1] = dp[1][2] = 1, dp[1][3] = 0;
for(int i = 2; i <= 130; i++)
{
dp[i][0] = (dp[i - 1][0] * 2 + dp[i - 1][1] + dp[i - 1][2]) % 10000;
dp[i][1] = (dp[i - 1][0]  + dp[i - 1][1] * 2 + dp[i - 1][3]) % 10000;
dp[i][2] = (dp[i - 1][0]  + dp[i - 1][2] * 2 + dp[i - 1][3]) % 10000;
dp[i][3] = (dp[i - 1][1] + dp[i - 1][2] + dp[i - 1][3] * 2) % 10000;
//    cout << i << " " << dp[i][0] % 100 << endl;
}
int T;
while(cin >> T)
{
if(T == 0)  break;
for(int cas = 1; cas <= T; cas++)
{
long long n;
cin >> n;
int ans = 0;
if(n <= 11) ans = dp
[0];
else  ans = dp[(n - 11) % (ll)20 + 11][0];
cout << "Case " << cas <<": " << ans % 100<< endl;
}
cout << endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: