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。

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

那么转移十分显然:fi,j=min{fi1,j+val1,fi,j1+val2}

其中 val1 表示将第 i 个白球放到 i+j 位置的最小花费, val2 对黑球同理。

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

cnti,j,0 表示在 posi,0 之后,编号前 i1 的白球和前 j 的黑球的数量,只有这些球是会到 posi,0 之前。我们可以先通过 cntk,0,0=cntk1,0,0+[posk,0<posk1,0] ,再通过 cnti,k,0=cnti,k1,0+[posi,0<posk,1] ,即可线性处理出 cnt

综上 val1=posi,0+cnti,j,0(i+j)val2=posj,1+cnti,j,1(i+j)

时间复杂度 O(n2)

空间复杂度 O(n2)

代码

#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 @   空白菌  阅读(92)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
点击右上角即可分享
微信分享提示