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

“红色病毒”问题

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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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[n][0];
      else  ans = dp[(n - 11) % (ll)20 + 11][0];
      cout << "Case " << cas <<": " << ans % 100<< endl;
    }
    cout << endl;
  }
  return 0;
}

你可能感兴趣的:(hdu,dp,HDU,acm,题解)