题目链接:http://codeforces.com/contest/1150/problem/D

题目大意:

你有一个参考串 s 和三个装载字符串的容器 vec[0..2] ,然后还有 q 次操作,每次操作你可以选择3个容器中的任意一个容器,往这个容器的末尾添加一个字符,或者从这个容器的末尾取出一个字符。

每一次操作之后,你都需要判断:三个容器的字符串能够表示成 s 的三个不重叠的子序列。

比如,如果你的参考串 s 是:

abdabc

而三个容器对应的字符串是:

  • vec[0]ad
  • vec[1]bc
  • vec[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)

但是我们注意到每次更新都知识更新三个容器中任意一个的一个值。

对于减字符串操作,我们不需要进行任何处理;

而对于增加字符串操作,我们假设三个容器的字符串个数分别为 N0N1N2,那么:

  • 当我们往 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 题解 动态规划的更多相关文章

  1. Codeforces Round #556 (Div. 2) - D. Three Religions(动态规划)

    Problem  Codeforces Round #556 (Div. 2) - D. Three Religions Time Limit: 3000 mSec Problem Descripti ...

  2. Codeforces Round #556 (Div. 2) - C. Prefix Sum Primes(思维)

    Problem  Codeforces Round #556 (Div. 2) - D. Three Religions Time Limit: 1000 mSec Problem Descripti ...

  3. Codeforces Round #556 (Div. 1)

    Codeforces Round #556 (Div. 1) A. Prefix Sum Primes 给你一堆1,2,你可以任意排序,要求你输出的数列的前缀和中质数个数最大. 发现只有\(2\)是偶 ...

  4. Codeforces Round #609 (Div. 2)前五题题解

    Codeforces Round #609 (Div. 2)前五题题解 补题补题…… C题写挂了好几个次,最后一题看了好久题解才懂……我太迟钝了…… 然后因为longlong调了半个小时…… A.Eq ...

  5. Codeforces Round #556 (Div. 2)

    比赛链接 A 贪心 #include <cstdlib> #include <cstdio> #include <algorithm> #include <c ...

  6. Codeforces Round #556 (Div. 2)-ABC(这次的题前三题真心水)

    A. Stock Arbitraging 直接上代码: #include<cstdio> #include<cstring> #include<iostream> ...

  7. 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 ...

  8. 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 ...

  9. Codeforces Round #272 (Div. 2) E. Dreamoon and Strings 动态规划

    E. Dreamoon and Strings 题目连接: http://www.codeforces.com/contest/476/problem/E Description Dreamoon h ...

随机推荐

  1. php自定义函数之回调函数

    回调函数,可以配合匿名函数和变量函数实现更加优美.复杂的一种函数结构.大理石平台价格 回调函数,就是在处理一个功能的时候,我让让这个功能自定义能力再强一些,我准许调用这个函数的时候,还可以传入一个函数 ...

  2. 010——MATLAB运行错误跳到下一个循环

    (一)MATLAB运行错误跳到下一个循环 :%文件的个数 try %运行的程序放到这里 catch continue%假如上面的没法执行则执行continue,到下个循环 end

  3. 转 Storm JAVA_HOME is incorrectly set.

    问题可能有两个原因: 1.在环境变量中未设置JAVA_HOME变量名称. 解决办法: 在环境变量中添加. 或者在storm中的bin文件下有一个storm-config.cmd,使用文本打开,查询JA ...

  4. 悬线法DP总结

    悬线法DP总结 问题模型 求满足某种条件(如01交替)的最大矩形(正方形) 思想 先预处理出\(ml[i][j],mr[i][j],mt[i][j]\),分别表示当前位置\((i,j)\)能向左扩展到 ...

  5. 模板 - 数学 - 数论 - Miller-Rabin算法

    使用Fermat小定理(Fermat's little theorem)的原理进行测试,不满足 \(2^{n-1}\;\mod\;n\;=\;1\) 的n一定不是质数:如果满足的话则多半是质数,满足上 ...

  6. jquery中$.get()如何让跨域请求携带cookie?

    在这个get请求前面加上这个就好了~~~~

  7. Linux压缩和解压类指令

    一.gzip / gunzip  指令 gzip 用于压缩文件,gunzip 用于解压文件. 基本语法gizp  文件 (功能描述:只能将文件压缩为*.gz文件)gunzip  文件.gz (功能描述 ...

  8. 分布式缓存Redis集群搭建

    redis安装 1.下载tar包至/opt/redis 2.解压tar包 tar -xvf redis-4.0.14.tar.gz 3. cd redis-4.0.14 make一下. 单节点的red ...

  9. IDEA_2019.2的安装与个人配置(Windows)

    1. 下载 官方下载网站:https://www.jetbrains.com/idea/download/ IDEA是支持多平台的开发工具,分为Windows.Mac和Linux三个平台,这里就只拿W ...

  10. T-MAX-冲刺总结

    T-MAX-冲刺总结 这个作业属于哪个课程 班级链接 这个作业要求在哪里 作业要求的链接 团队名称 T-MAX 这个作业的目标 冲刺总结 作业的正文 T-MAX-冲刺总结 其他参考文献 面向B站,百度 ...