NC19832 1408

题目链接

题目

题目描述

小m曾经给小t和小s讲过一个奇怪的故事。这个故事叫做1408。故事的大体内容如下。

主人公迈克·安瑟林(约翰·库萨克饰)是一个恐怖小说家。将装神弄鬼作为本职工作的迈克,平日里却是个彻头彻尾的无神论者。为了完成自己的新书,迈克决定找一家“闹鬼”

的房间住上十天,而胆大包天的他最终选择了传闻中最阴森恐怖的海豚酒店的1408号房间。

酒店经理杰拉尔德·奥林(塞缪尔·杰克逊饰)拿出在那个房间中历年来数十起离奇死亡事件的照片,来力劝迈克不要冒险,但迈克满不在乎,坚持着自己的选择。而在搬进1408号房间后,一件件离奇的超自然现象让迈克彻底改变了自己的鬼神人生观。大量恐怖惊悚的真实体验为迈克的新书着实积累了素材,但问题的关键是,他必须得先活着走出那个房间。

以上写的只是简介,实际这个故事细思极恐。而由于小s当时住的宾馆是14楼,所以他有一点点慌。于是回房间之后根小b玩起了一个游戏。

游戏是这样的,小s有n个白球和n个黑球,白球和黑球的编号分别1~n排序。给你2*n行信息,每行第一个是一个字符,B表示它是黑球,W表示它是白球,后面的一个数字表示这个球在它自己的颜色中的编号。每一次可以交换相邻两个球的位置。问北神最少移动几次可以使得对于所有白球,序号是按顺序排列的且所有黑球的序号也是按顺序排列的。

小b觉得这个问题很有意思,所以也请你来做做。

输入描述

输入一个数n,之后给你2*n行信息,信息内容见题面。

输出描述

输出最小的交换次数

示例1

输入

3
B 1
W 2
B 3
W 1
W 3
B 2

输出

4

备注

对于10%的数据n<=10

对于100%的数据n<=2000

题解

知识点:线性dp。

考虑设 \(f_{i,j}\) 表示已经排好了编号前 \(i\) 个白球前 \(j\) 个黑球的最小操作次数。

那么转移十分显然:\(f_{i,j} = \min\{ f_{i-1,j} + val_1, f_{i,j-1}+val_2 \}\)

其中 \(val_1\) 表示将第 \(i\) 个白球放到 \(i+j\) 位置的最小花费, \(val_2\) 对黑球同理。

不妨我们考虑 \(val_1\) ,我们只需要知道第 \(i\) 个白球位置到 \(i+j\) 的距离即可。设 \(pos_{i,0}\) 表示白球原来的位置。因为前 \(i-1\) 个白球前 \(j\) 个黑球移动了,所以第 \(i\) 个白球的实际位置也是会变的。

\(cnt_{i,j,0}\) 表示在 \(pos_{i,0}\) 之后,编号前 \(i-1\) 的白球和前 \(j\) 的黑球的数量,只有这些球是会到 \(pos_{i,0}\) 之前。我们可以先通过 \(cnt_{k,0,0} = cnt_{k-1,0,0} + [pos_{k,0} < pos_{k-1,0}]\) ,再通过 \(cnt_{i,k,0} = cnt_{i,k-1,0} + [pos_{i,0} < pos_{k,1}]\) ,即可线性处理出 \(cnt\)

综上 \(val_1 = pos_{i,0} + cnt_{i,j,0} - (i+j)\)\(val_2 = pos_{j,1} + cnt_{i,j,1} -(i+j)\)

时间复杂度 \(O(n^2)\)

空间复杂度 \(O(n^2)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int pos[2007][2];
int cnt[2007][2007][2]; // 放了前i-1个白球,前j个黑球,第i个白(第j个黑球)球右边有几个球到它前面
int f[2007][2007];
int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    for (int i = 1;i <= 2 * n;i++) {
        char ch;
        int id;
        cin >> ch >> id;
        pos[id][ch == 'B'] = i;
    }
    for (int i = 1;i <= n;i++) {
        for (int j = 1;j < i;j++) {
            cnt[i][0][0] += pos[i][0] < pos[j][0];
            cnt[0][i][1] += pos[i][1] < pos[j][1];
        }
        for (int j = 1;j <= n;j++) {
            cnt[i][j][0] = cnt[i][j - 1][0] + (pos[i][0] < pos[j][1]);
            cnt[j][i][1] = cnt[j - 1][i][1] + (pos[i][1] < pos[j][0]);
        }
        f[i][0] = f[i - 1][0] + pos[i][0] + cnt[i][0][0] - i;
        f[0][i] = f[0][i - 1] + pos[i][1] + cnt[0][i][1] - i;
    }
    for (int i = 1;i <= n;i++)
        for (int j = 1;j <= n;j++)
            f[i][j] = min
            (
                f[i - 1][j] + pos[i][0] + cnt[i][j][0] - (i + j),
                f[i][j - 1] + pos[j][1] + cnt[i][j][1] - (i + j)
            );
    cout << f[n][n] << '\n';
    return 0;
}
posted @ 2023-08-28 01:17  空白菌  阅读(57)  评论(0编辑  收藏  举报