首页 > 技术文章 > P1136 迎接仪式

StarRoadTang 2020-10-21 05:28 原文

题目链接

点我跳转

题目大意

给定一个长度为 \(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 << '\n';
	return 0;
}

推荐阅读