P1136 迎接仪式

题目链接

点我跳转

题目大意

给定一个长度为 (N) 的字符串 (S)(S) 仅由字符 (j , z) 组成

现在你最多可以执行 (0)(K) 次操作,每次操作可以选择字符串任意两个位置的字符将它们的位置交换

问最多可以组成多少对相邻的 ((j,z))

解题思路

很巧妙的一道题

定义 (dp[i][j][k][l])(1≤i,j,k≤N)(0≤l≤2)

其中 (dp[i][j][k][0]) 表示前 (i) 个字符,改变了 (j) 个字符 (j)(k) 个字符 (z),且将第 (i) 位字符变为 (j) 的最优解

(dp[i][j][k][0]) 表示前 (i) 个字符,改变了 (j) 个字符 j,(k) 个字符 (z),且将第 (i) 位字符变为 (z) 的最优解

那么不难得到 :

(s[i] = j)

(dp[i][j][k][0] = max(dp[i - 1][j][k][0] , dp[i - 1][j][k][1]))

(dp[i][j][k][1] = max(dp[i - 1][j - 1][k][0] + 1 , dp[i - 1][j - 1][k][1]))

(s[i] = z)

(dp[i][j][k][0] = max(dp[i - 1][j][k - 1][0] , dp[i - 1][j][k - 1][1]))

(dp[i][j][k][1] = max(dp[i - 1][j][k][0] + 1 , dp[i - 1][j][k][1]))

最后只要枚举 (j , k)(j = k) 时更新答案即可

AC_Code

#include<bits/stdc++.h>
using namespace std;
const int M = 5e2 + 10 , MM = 1e2 + 10;
int dp[M][MM][MM][2];
char s[M];
signed main()
{
	ios::sync_with_stdio(false);
	int n , m;
	cin >> n >> m >> s + 1;
	memset(dp , 128 , sizeof dp);
	dp[0][0][0][1] = 0;
	for(int i = 1 ; i <= n ; i ++)
	{
		for(int j = 0 ; j <= m ; j ++) for(int k = 0 ; k <= m ; k ++)
		{
			if(s[i] == 'j')
			{
				int b = max(dp[i - 1][j][k][0] , dp[i - 1][j][k][1]);
				dp[i][j][k][0] = max(dp[i][j][k][0] ,  b);
				int d = -0x3f3f3f3f;
				if(j) d = max(dp[i - 1][j - 1][k][0] + 1 , dp[i - 1][j - 1][k][1]);
				dp[i][j][k][1] = max(dp[i][j][k][1] , d);
			}
			else
			{
				int b = -0x3f3f3f3f;
				if(k) b = max(dp[i - 1][j][k - 1][0] , dp[i - 1][j][k - 1][1]);
				dp[i][j][k][0] = max(dp[i][j][k][0] , b);
				int d = max(dp[i - 1][j][k][0] + 1 , dp[i - 1][j][k][1]);
				dp[i][j][k][1] = max(dp[i][j][k][1] , d);
			}
		}
	}
	int res = 0;
	for(int j = 0 ; j <= m ; j ++) for(int k = 0 ; k <= m ; k ++)
	{
		if(j == k) res = max(res , max(dp[n][j][k][0] , dp[n][j][k][1]));
	}
	cout << res << '
';
	return 0;
}
原文地址:https://www.cnblogs.com/StarRoadTang/p/13850107.html