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 }