CW 11.02 模拟赛 FSYo T2
题面
自出题
挂个 pdf
题面下载
算法
看到交换, 这里有一个套路:
确定最终的形态后, 交换次数即为逆序对个数
我们直接设 \(f_{i, j, k, 0 / 1 / 2}\) 表示 \(3\) 种颜色填到哪里了,最后一个是什么颜色,逆序对数最少是多少
转移分最后一个是什么颜色讨论
关于 \(O(1)\) 求逆序对的方法:
if(i==0 && a) f[a][b][c][0] = min(f[a][b][c][0], min(f[a-1][b][c][1], f[a-1][b][c][2])+max(0, b-pre[0][a].first)+max(0, c-pre[0][a].second));
if(i==1 && b) f[a][b][c][1] = min(f[a][b][c][1], min(f[a][b-1][c][0], f[a][b-1][c][2])+max(0, a-pre[1][b].first)+max(0, c-pre[1][b].second));
if(i==2 && c) f[a][b][c][2] = min(f[a][b][c][2], min(f[a][b][c-1][0], f[a][b][c-1][1])+max(0, a-pre[2][c].first)+max(0, b-pre[2][c].second));
\(O(n ^ 3)\)
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 202;
const int N = 505;
const int INF = 1e9;
int n, f[maxn][maxn][maxn][3], pos[3];
pair<int, int> pre[3][maxn];
char s[402];
inline ll read()
{
ll x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
{
f = -1;
}
ch = getchar();
}
while (ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
int main()
{
freopen("s.in", "r", stdin);
freopen("s.out", "w", stdout);
n = read();
scanf("%s", s + 1);
for (int i = 1; i <= n; i++)
{
if (s[i] == 'R')
pos[0]++, pre[0][pos[0]] = make_pair(pos[1], pos[2]);
else if (s[i] == 'G')
pos[1]++, pre[1][pos[1]] = make_pair(pos[0], pos[2]);
else
pos[2]++, pre[2][pos[2]] = make_pair(pos[0], pos[1]);
}
memset(f, 0x3f, sizeof(f));
if (pos[0])
f[1][0][0][0] = 0;
if (pos[1])
f[0][1][0][1] = 0;
if (pos[2])
f[0][0][1][2] = 0;
for (int a = 0; a <= pos[0]; a++)
{
for (int b = 0; b <= pos[1]; b++)
{
for (int c = 0; c <= pos[2]; c++)
{
for (int i = 0; i <= 2; i++)
{
if (i == 0 && a)
f[a][b][c][0] = min(f[a][b][c][0], min(f[a - 1][b][c][1], f[a - 1][b][c][2]) + max(0, b - pre[0][a].first) + max(0, c - pre[0][a].second));
if (i == 1 && b)
f[a][b][c][1] = min(f[a][b][c][1], min(f[a][b - 1][c][0], f[a][b - 1][c][2]) + max(0, a - pre[1][b].first) + max(0, c - pre[1][b].second));
if (i == 2 && c)
f[a][b][c][2] = min(f[a][b][c][2], min(f[a][b][c - 1][0], f[a][b][c - 1][1]) + max(0, a - pre[2][c].first) + max(0, b - pre[2][c].second));
}
}
}
}
printf("%d\n", min(f[pos[0]][pos[1]][pos[2]][0], min(f[pos[0]][pos[1]][pos[2]][1], f[pos[0]][pos[1]][pos[2]][2])));
return 0;
}
总结
算套路吧(?)
逆序对求法值得学习, 类似于前缀和