Acdream1201 SuSu's Power

題目:SuSu's Power

鏈接:http://acdream.info/problem?pid=1201

題意:一個人站在x軸原點上,初始方向向x軸正方向,由一個字符串來控制其運動,字符串由A、B組成,A表示前進一步,B表示反向,給出字符串,問修改m次字符的情況下,人離原點最遠多少?(可以重複修改一個字符,可令 A變B 或 B變A)

思路:

  最近區間DP做多了,試了好久的區間DP。。。後來發現根本不需要用它(用了時間複雜度太高了。),因爲必須把字符串完整用完,所以從第一個字符開始遞推就可以了。後來改了方法,又因爲不知道m次可以針對同一個字符,錯了好多次(思路也基本固定了,後來按原來思路稍加修改居然闖下來了)。。。

  首先,我假定m次必須用完(。。。強裝我是故意的),用dp[105][55][2][2]計算,第一維表示下標,第二維表示修改次數,第三維表示方向(向右/向左),第四維表示最大或最小,dp[i][j][0][0]就表示解決前i 個字符,修改j次,當前方向是0的最大值(不是距離)。

  現在遞推式就很簡單了,按正常邏輯寫就可以了,最終M次的答案就是dp[n-1][m][0][0], 01, 10, 11四個的絕對值求最大,必須都考慮,不能認爲方向0的最大值一定是正數,舉個例子BAB 0。

  最後解決m次可以改變同一字符的情況,假如我改了第一個字符兩次,就相當於m=m-2,所以取他們的較大值即可。

AC代碼:

  1 #include<stdio.h>
  2 #include<algorithm>
  3 using namespace std;
  4 #define N 105
  5 #define M 55
  6 #define INF 1e9
  7 /*
  8   dp[i][j][k][x]:
  9   i前,修改j次,當前是加/減,最大值/最小值
 10 */
 11 int dp[N][M][2][2];
 12 void initdp()
 13 {
 14   for(int i=0; i<N; i++){
 15     for(int j=0; j<M; j++){
 16       for(int k=0; k<2; k++){
 17         for(int u=0; u<2; u++){
 18           dp[i][j][k][u]=-INF;
 19         }
 20       }
 21     }
 22   }
 23 }
 24 int add(int x, int y){
 25   if(x==-INF) return -INF;
 26   return x+y;
 27 }
 28 int min(int x, int y)
 29 {
 30   if(x==-INF && y==-INF) return -INF;
 31   else if(x==-INF) return y;
 32   else if(y==-INF) return x;
 33   else return x<y?x:y;
 34 }
 35 int main()
 36 {
 37   int n, m, cas=1;
 38   char s[N];
 39   while(~scanf("%d", &n)){
 40     scanf("%s%d", s, &m);
 41     initdp();
 42     if(s[0]=='A'){
 43       dp[0][0][0][0]=1;
 44       dp[0][0][0][1]=1;
 45       dp[0][1][1][0]=0;
 46       dp[0][1][1][1]=0;
 47     }
 48     else{
 49       dp[0][0][1][0]=0;
 50       dp[0][0][1][1]=0;
 51       dp[0][1][0][0]=1;
 52       dp[0][1][0][1]=1;
 53     }
 54     for(int i=1; i<n; i++){
 55       if(s[i]=='A'){
 56         dp[i][0][0][0]=add(dp[i-1][0][0][0],1);
 57         dp[i][0][0][1]=add(dp[i-1][0][0][1],1);
 58         dp[i][0][1][0]=add(dp[i-1][0][1][0],-1);
 59         dp[i][0][1][1]=add(dp[i-1][0][1][1],-1);
 60         for(int k=1; k<=m && k<=i+1; k++){
 61           dp[i][k][0][0]=max(add(dp[i-1][k][0][0], 1), dp[i-1][k-1][1][0]);
 62           dp[i][k][0][1]=min(add(dp[i-1][k][0][1], 1), dp[i-1][k-1][1][1]);
 63           dp[i][k][1][0]=max(add(dp[i-1][k][1][0], -1), dp[i-1][k-1][0][0]);
 64           dp[i][k][1][1]=min(add(dp[i-1][k][1][1], -1), dp[i-1][k-1][0][1]);
 65         }
 66       }
 67       else
 68       {
 69         dp[i][0][0][0]=dp[i-1][0][1][0];
 70         dp[i][0][0][1]=dp[i-1][0][1][1];
 71         dp[i][0][1][0]=dp[i-1][0][0][0];
 72         dp[i][0][1][1]=dp[i-1][0][0][1];
 73         for(int k=1; k<=m && k<=i+1; k++){
 74           dp[i][k][0][0]=max(add(dp[i-1][k-1][0][0], 1), dp[i-1][k][1][0]);
 75           dp[i][k][0][1]=min(add(dp[i-1][k-1][0][1], 1), dp[i-1][k][1][1]);
 76           dp[i][k][1][0]=max(add(dp[i-1][k-1][1][0], -1), dp[i-1][k][0][0]);
 77           dp[i][k][1][1]=min(add(dp[i-1][k-1][1][1], -1), dp[i-1][k][0][1]);
 78         }
 79       }
 80     }
 81 
 82     //int x, y, z, k;
 83     //while(~scanf("%d%d%d%d", &x, &y, &z, &k)){
 84     //  printf("==> %d\n", dp[x][y][z][k]);
 85     //}
 86 
 87     int ans=-INF;
 88     while(m>=0)
 89     {
 90       int tmp=-INF;
 91       if(dp[n-1][m][1][1]!=-INF && dp[n-1][m][0][0]!=-INF)
 92         tmp=max(abs(dp[n-1][m][0][0]), abs(dp[n-1][m][1][1]));
 93       else if(dp[n-1][m][0][0]!=-INF) tmp=abs(dp[n-1][m][0][0]);
 94       else if(dp[n-1][m][1][1]!=-INF) tmp=abs(dp[n-1][m][1][1]);
 95 
 96       if(dp[n-1][m][1][0]!=-INF && dp[n-1][m][0][1]!=-INF) tmp = max(tmp, max(abs(dp[n-1][m][0][1]), abs(dp[n-1][m][1][0])));
 97       else if(dp[n-1][m][1][0]!=-INF) tmp=max(tmp, abs(dp[n-1][m][1][0]));
 98       else if(dp[n-1][m][0][1]!=-INF) tmp=max(tmp, abs(dp[n-1][m][0][1]));
 99 
100       ans=max(ans, tmp);
101       m-=2;
102     }
103 
104     printf("Case #%d: %d\n", cas++, ans);
105   }
106   return 0;
107 }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章