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 }

 

posted @ 2017-03-21 15:58  hchlqlz  阅读(346)  评论(0编辑  收藏  举报