https://vjudge.net/problem/CodeForces-132C
题意: F表示向前走,T表示向后转,有N次修改字符的机会,问最多能走多远
思路:dp[ i ][ j ][ d ]表示前i个字符修改了j次,走了k长度,当前朝向是d的状态的最大长度
所以就可以递推一个关系式,分第i个字符为‘F‘ or ‘T‘时
然后多维递推dp就是当前 i、j都是由 老i、j递推出来的,即 i-1,j-k,其实就是记忆化暴力。
注意:要用max就得先全部初始化为-inf,然后dp[0][0][1]、dp[0][0][0] 初始化为0,还要注意 j、k枚举的始末是从0到n、j。
#include <iostream> #include <cstdio> #include <string> #include <cstring> #include <vector> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <algorithm> using namespace std; const int maxn=110; const int inf = 0x3f3f3f3f; char s[maxn]; int n; int dp[110][55][2]; //表示状态 前i位前j个操作后的朝向 (0正1负) int main(){ scanf("%s",s+1); scanf("%d",&n); int len = strlen(s+1); for(int i=0; i<=len; i++){ for(int j=0; j<=n; j++){ dp[i][j][1] = dp[i][j][0] = -inf; } } dp[0][0][1]=dp[0][0][0]=0; //初始化以及j、k的循环始末要想仔细 //记忆化暴力 for(int i=1; i<=len; i++){ for(int j=0; j<=n; j++){ //前j个操作是从前j-k个操作(前i-1位的)递推来的 for(int k=0; k<=j; k++){ //选择性分配 if(s[i]=='T'){ if(k&1){ //多维dp,把i、j用相似的递推思想处理 dp[i][j][0] = max(dp[i][j][0], dp[i-1][j-k][0]+1); dp[i][j][1] = max(dp[i][j][1], dp[i-1][j-k][1]-1); } else{ dp[i][j][0] = max(dp[i][j][0], dp[i-1][j-k][1]); dp[i][j][1] = max(dp[i][j][1], dp[i-1][j-k][0]); } } else{ if(k&1){ dp[i][j][0] = max(dp[i][j][0], dp[i-1][j-k][1]); dp[i][j][1] = max(dp[i][j][1], dp[i-1][j-k][0]); } else{ dp[i][j][0] = max(dp[i][j][0], dp[i-1][j-k][0]+1); dp[i][j][1] = max(dp[i][j][1], dp[i-1][j-k][1]-1); } } } } } printf("%d ", max(dp[len][n][0], dp[len][n][1])); return 0; }