CodeForces 790C Bear and Company
题目描述:
输入一个字符串,你可以进行一些操作,每次操作可以交换两个相邻的字符。问至少进行几次操作,才能使这个字符串不包含子串 VK 。
题解:
我们发现其实字符串中的字符只有三种:V ,K ,和其它的(至于是 A 、 B 、 C 还是什么其实并不影响)。
令 dpi,j,k,v 表示将前 i 个 V ,前 j 个 K ,前 k 个其它字符全部转移到字符串的最前面的代价, v 表示最后一个字符是不是 V 。然后大力 DP 就行。
本题 O(n4) 可做,但实际 O(n3) 就行。
代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 100
static int N;
static int pos[3][MAXN], num[3][MAXN], dp[MAXN][MAXN][MAXN][2];
static char S[MAXN];
inline int move(int i, int j, int k, int p)
{
return max(0, num[0][p] - i) + max(0, num[1][p] - j) + max(0, num[2][p] - k) - 1;
}
int main()
{
scanf("%d%s", &N, S + 1);
for (int i = 1; i <= N; i++)
{
num[0][i] = num[0][i-1];
num[1][i] = num[1][i-1];
num[2][i] = num[2][i-1];
if (S[i] == 'V')
pos[0][num[0][i]++] = i;
else if (S[i] == 'K')
pos[1][num[1][i]++] = i;
else
pos[2][num[2][i]++] = i;
}
memset(dp, 0x3f, sizeof(dp));
dp[0][0][0][0] = 0;
for (int i = 0; i <= num[0][N]; i++)
for (int j = 0; j <= num[1][N]; j++)
for (int k = 0; k <= num[2][N]; k++)
for (int is_v = 0; is_v < 2; is_v++)
{
if (i < num[0][N])
dp[i+1][j][k][1] = min(dp[i+1][j][k][1], dp[i][j][k][is_v] + move(i, j, k, pos[0][i]));
if (j < num[1][N] && !is_v)
dp[i][j+1][k][0] = min(dp[i][j+1][k][0], dp[i][j][k][is_v] + move(i, j, k, pos[1][j]));
if (k < num[2][N])
dp[i][j][k+1][0] = min(dp[i][j][k+1][0], dp[i][j][k][is_v] + move(i, j, k, pos[2][k]));
}
printf("%d\n", min(dp[num[0][N]][num[1][N]][num[2][N]][0], dp[num[0][N]][num[1][N]][num[2][N]][1]));
return 0;
}
提交记录(AC / Total = 1 / 1):
Run ID | Remote Run ID | Time(ms) | Memory(kb) | Result | Submit Time |
---|---|---|---|---|---|
8512202 | 25686761 | 15 | 9680 | AC | 2017-03-21 19:29:10 |