Before the Beginning

转载请将本段放在文章开头显眼处,如有二次创作请标明。
原文链接:https://www.codein.icu/nowcoderweekly16/

似乎网上没这道题题解,于是全场……
一开始看错题了,以为黑白球必须分别扎堆,其实不需要。
可以使用动态规划来解决,由于要求顺序,那么:
设前 个球中,有 个白球, 个黑球,那么对应的黑白球编号一定是
此时决定第 个球,选择白球或者黑球进行转移,即满足了最优子结构。
为前 个球, 个白球, 个黑球的状态。
如果决定第 个球为白球,,其中 为编号为 的球移到 的代价。
黑球同理。
考虑如何计算这个代价,显然可以记录 代表编号为 的球的坐标,代价即
然而在前面的过程中,即移动前 个球时, 可能发生了变化。
如果移动的球在 前,则对其无影响,如果在其后,则
统计当前状态,编号 的白球与 的黑球中,有多少个在 中,即可知道该球的 向后了多少。
计算出相应代价进行DP即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <ctype.h>
const int maxn = 4e3 + 100;
int n;
int wnum,bnum;
char s[10];
int f[maxn][maxn];//前i个,白色前j个
int id[maxn],col[maxn];
int wpos[maxn],bpos[maxn];
int wcnt[maxn][maxn],bcnt[maxn][maxn];
inline int getw(int l,int r,int x){return wcnt[r][x] - wcnt[l - 1][x];}
inline int getb(int l,int r,int x){return bcnt[r][x] - bcnt[l - 1][x];}
int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n * 2; ++i)
    {
        scanf("%s", s + 1), scanf("%d", id + i);
        col[i] = (s[1] == 'B');
        if(col[i]) bpos[id[i]] = i;
        else wpos[id[i]] = i;
    }
    for(int i = 1;i<=2*n;++i) 
    {
        if (col[i] == 0) for (int j = id[i]; j <= n; ++j) wcnt[i][j]++;
        else for (int j = id[i]; j <= n; ++j) bcnt[i][j]++;
        for (int j = 1; j <= n; ++j) wcnt[i][j] += wcnt[i - 1][j], bcnt[i][j] += bcnt[i - 1][j];
    }
    memset(f, 0x3f, sizeof(f));
    f[0][0] = 0;
    for (int i = 1; i <= 2 * n; ++i)
    {
        for (int j = 0; j <= n && j <= i; ++j)
        {
            int bl = i - j;
            if (j <= i - 1)
            {
                //choose black to fill i
                int bp = bpos[bl];
                f[i][j] = f[i - 1][j] + bp - i + getw(bp + 1, 2 * n, j) + getb(bp + 1, 2 * n, bl - 1);
            }
            if (j)
            {
                //choose white to fill i
                int wp = wpos[j];
                f[i][j] = std::min(f[i][j], f[i - 1][j - 1] + wp - i + getw(wp + 1, 2 * n, j - 1) + getb(wp + 1, 2 * n, bl));
            }
        }
    }
    printf("%d\n",f[2*n][n]);
    return 0;
}