Codeforces Round #556 (Div. 2) D. Three Religions 题解 动态规划
题目链接:http://codeforces.com/contest/1150/problem/D
题目大意:
你有一个参考串 s 和三个装载字符串的容器 vec[0..2] ,然后还有 q 次操作,每次操作你可以选择3个容器中的任意一个容器,往这个容器的末尾添加一个字符,或者从这个容器的末尾取出一个字符。
每一次操作之后,你都需要判断:三个容器的字符串能够表示成 s 的三个不重叠的子序列。
比如,如果你的参考串 s 是:
abdabc
而三个容器对应的字符串是:
vec[0]:advec[1]:bcvec[2]:ab
那么是三个容器是可以凭借成 s 的三个不重叠的子序列的,如图:

题目分析:
首先如果不是q次询问的话,那么这道题目乍看起来应该是可以使用dp或者网络流来进行求解的。
那么这道题目用dp比较好解。
首先我们需要开一个 nxt[N][26] 的数组,nxt[i][j] 表示以字符串 s[i] 开始第一个出现字符 'a'+j 的位置。N 表示字符串 s 的长度。
那么我们可以用 O(N*26) 的时间初始化这个数组。
然后我们开一个三维数组 dp[250][250][250] ,其中 dp[n0][n1][n2] 表示 字符串 s 匹配到 vec[0][n0]、vec[1][n1]、vec[2][n2] 的最小坐标。
那么我们就能够无推断出状态转移方程:
if (!i && !j && !k) dp[0][0][0] = -1;
else {
if (i && dp[i-1][j][k]+1 < N && nxt[dp[i-1][j][k]+1][vec[0][i-1]-'a'] != INF) {
dp[i][j][k] = min(dp[i][j][k], nxt[dp[i-1][j][k]+1][vec[0][i-1]-'a']);
}
if (j && dp[i][j-1][k]+1 < N && nxt[dp[i][j-1][k]+1][vec[1][j-1]-'a'] != INF) {
dp[i][j][k] = min(dp[i][j][k], nxt[dp[i][j-1][k]+1][vec[1][j-1]-'a']);
}
if (k && dp[i][j][k-1]+1 < N && nxt[dp[i][j][k-1]+1][vec[2][k-1]-'a'] != INF) {
dp[i][j][k] = min(dp[i][j][k], nxt[dp[i][j][k-1]+1][vec[2][k-1]-'a']);
}
}
我们可以用 O(250^3) 的时间复杂度求得一个答案,然后对于q次询问,时间复杂度是 O(250^3*q),
但是我们注意到每次更新都知识更新三个容器中任意一个的一个值。
对于减字符串操作,我们不需要进行任何处理;
而对于增加字符串操作,我们假设三个容器的字符串个数分别为 N0、N1和N2,那么:
- 当我们往
vec[0]中添加了一个元素之后,我们除了N0++操作以外,只需要更新dp[N0][0][0]到dp[N0][N1][N2]; - 当我们往
vec[1]中添加了一个元素之后,我们除了N1++操作以外,只需要更新dp[0][N1][0]到dp[N0][N1][N2]; - 当我们往
vec[2]中添加了一个元素之后,我们除了N2++操作以外,只需要更新dp[0][0][N2]到dp[N0][N1][N2]。
所以其实对于每一次询问,我们都只需要进行 O(250^2) 就可以了。
那么最终我们将这道题目的时间复杂度降到了 O(q*250^2) 。
代码:
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
using namespace std;
#define INF (1<<29)
int dp[255][255][255], n[3], nxt[100005][26], N, q;
vector<char> vec[3];
string s;
void init() {
for (int i = 0; i < 26; i ++) {
int idx = INF;
for (int j = N-1; j >= 0; j --) {
char c = (char)('a' + i);
if (s[j] == c)
idx = j;
nxt[j][i] = idx;
}
}
}
void cal(int n0, int n1, int n2) {
for (int i = n0; i <= n[0]; i ++) {
for (int j = n1; j <= n[1]; j ++) {
for (int k = n2; k <= n[2]; k ++) {
dp[i][j][k] = INF;
if (!i && !j && !k) dp[0][0][0] = -1;
else {
if (i && dp[i-1][j][k]+1 < N && nxt[dp[i-1][j][k]+1][vec[0][i-1]-'a'] != INF) {
dp[i][j][k] = min(dp[i][j][k], nxt[dp[i-1][j][k]+1][vec[0][i-1]-'a']);
}
if (j && dp[i][j-1][k]+1 < N && nxt[dp[i][j-1][k]+1][vec[1][j-1]-'a'] != INF) {
dp[i][j][k] = min(dp[i][j][k], nxt[dp[i][j-1][k]+1][vec[1][j-1]-'a']);
}
if (k && dp[i][j][k-1]+1 < N && nxt[dp[i][j][k-1]+1][vec[2][k-1]-'a'] != INF) {
dp[i][j][k] = min(dp[i][j][k], nxt[dp[i][j][k-1]+1][vec[2][k-1]-'a']);
}
}
}
}
}
}
int main() {
cin >> N >> q >> s;
init();
cal(0, 0, 0);
while (q --) {
string tmps1, tmps2;
int tmpnum;
cin >> tmps1 >> tmpnum;
if (tmps1 == "+") {
cin >> tmps2;
vec[tmpnum-1].push_back(tmps2[0]);
n[tmpnum-1] ++;
switch(tmpnum) {
case 1:
cal(n[0], 0, 0);
break;
case 2:
cal(0, n[1], 0);
break;
case 3:
cal(0, 0, n[2]);
break;
}
} else {
n[tmpnum-1] --;
vec[tmpnum-1].pop_back();
}
cout << ( dp[n[0]][n[1]][n[2]] == INF ? "NO" : "YES" ) << endl;
}
return 0;
}
Codeforces Round #556 (Div. 2) D. Three Religions 题解 动态规划的更多相关文章
- Codeforces Round #556 (Div. 2) - D. Three Religions(动态规划)
Problem Codeforces Round #556 (Div. 2) - D. Three Religions Time Limit: 3000 mSec Problem Descripti ...
- Codeforces Round #556 (Div. 2) - C. Prefix Sum Primes(思维)
Problem Codeforces Round #556 (Div. 2) - D. Three Religions Time Limit: 1000 mSec Problem Descripti ...
- Codeforces Round #556 (Div. 1)
Codeforces Round #556 (Div. 1) A. Prefix Sum Primes 给你一堆1,2,你可以任意排序,要求你输出的数列的前缀和中质数个数最大. 发现只有\(2\)是偶 ...
- Codeforces Round #609 (Div. 2)前五题题解
Codeforces Round #609 (Div. 2)前五题题解 补题补题…… C题写挂了好几个次,最后一题看了好久题解才懂……我太迟钝了…… 然后因为longlong调了半个小时…… A.Eq ...
- Codeforces Round #556 (Div. 2)
比赛链接 A 贪心 #include <cstdlib> #include <cstdio> #include <algorithm> #include <c ...
- Codeforces Round #556 (Div. 2)-ABC(这次的题前三题真心水)
A. Stock Arbitraging 直接上代码: #include<cstdio> #include<cstring> #include<iostream> ...
- Codeforces Round #335 (Div. 2) C. Sorting Railway Cars 动态规划
C. Sorting Railway Cars Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.codeforces.com/conte ...
- Codeforces Round #370 (Div. 2) D. Memory and Scores 动态规划
D. Memory and Scores 题目连接: http://codeforces.com/contest/712/problem/D Description Memory and his fr ...
- Codeforces Round #272 (Div. 2) E. Dreamoon and Strings 动态规划
E. Dreamoon and Strings 题目连接: http://www.codeforces.com/contest/476/problem/E Description Dreamoon h ...
随机推荐
- luoguP3768简单的数学题
大佬们绕道吧(或跳到错误&启发后下一根横线后) 这道题吧正解是莫比乌斯反演吧,但本人有一种独创玄妙的想法去偏分 这道题是让我们求这个对吧 \((\sum_{i=1}^n\sum_{j=1}^n ...
- Windows异常相关数据结构
当一个异常发生时,操作系统要向引起异常的线程的栈里压入三个结构,这三个结构是:E X C E P T I O N _ R E C O R D结构.C O N T E X T结构和E X C E P T ...
- Ubuntu 系统安装教程
- [SCOI2016]妖怪
嘟嘟嘟 离NOI最后一周,把自己容易忘的知识点和板子复习一下. (刚答完loj的笔试模拟,感觉上不了90--) update:哦,我89-- 先把式子写出来,每一个妖怪的战斗力\(S(i) = A + ...
- 2D到3D视频转换 三维重建
2D到3D视频转换(也称为2D到立体3D转换和立体转换)是将2D(“平面”)胶片转换为3D形式的过程,几乎在所有情况下都是立体声,因此它是创建图像的过程.每个眼睛来自一个2D图像. 内容 1概述 1. ...
- ZR#1015
ZR#1015 解法: 我们需要求得, $ g_i $ 表示长度为的最长不下降子序列个数. 设 $ f_{i,j} $ 表示统计第前$ i $ 个数字,得到最长不下降子序列末端为 $ j $ . 显然 ...
- Kafka(二) —— Server端设计原理
整理架构 kafka confluence kafka官方文档中文翻译-设计 消息设计 /** * 消息类 * * @author Michael Fang * @since 2019-11-14 * ...
- RabbitMQ入门学习系列(二),单生产者消费者
友情提示 我对我的文章负责,发现好多网上的文章 没有实践,都发出来的,让人走很多弯路,如果你在我的文章中遇到无法实现,或者无法走通的问题.可以直接在公众号<爱码农爱生活 >留言.必定会再次 ...
- JavaScript初探系列目录
一 系列导航 结合各方面的参考资料,整理出来以下主要目录,供方便浏览查看 (一)初探系列 JavaScript初探系列(1)——基本概念 JavaScript初探系列(2)——数 ...
- JMS与消息队列
JMS,Java Message Service,即Java消息服务. MOM,Message Oriented Miiddleware的英文缩写,指的是利用高效可靠的消息传递机制进行平台无关的数据交 ...