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

Problem  Codeforces Round #556 (Div. 2) - D. Three Religions

Time Limit: 3000 mSec

Problem Description

Input

Output

Sample Input

6 8
abdabc
+ 1 a
+ 1 d
+ 2 b
+ 2 c
+ 3 a
+ 3 b
+ 1 c
- 2

Sample Output

YES
YES
YES
YES
YES
YES
NO
YES

题解:动态规划,意识到这个题是动态规划之后难点在于要优化什么东西,本题是让判断原串能否划分成题中不断更新的三个字符串,通常情况下dp数组不仅仅记录true/false这种信息,因为这种信息往往可以在不改变复杂度的情况下通过记录更具体的信息来直接导出,而这些更具体的信息会给状态的转移带来便利,本题就是这样的情况。

  意识到本题的dp属于分段决策同样很重要,对于当前的三个字符串,判断是否合法的方式是逐个加入字符,逐个加入的过程就是天然的阶段,而每个阶段需要做出的决策是加入哪一个字符串的字符,在这个过程中维护的信息就是把第一个串的前 a 个字符,第二个串的前 b 个字符,第三个串的前 c 个字符放进去所需要原串的最小长度。

  有了这样的状态定义转移方程自然很简单,比如考虑dp[a][b][c],并且是从dp[a-1][b][c]转移过来的,那么dp[a][b][c]就是在dp[a-1][b][c]位置之后第一次出现第一个串第a个字符的位置,为了能够O(1)转移,预处理出对于原串的每个位置i,对每个小写英文字母x,i及i以后第一次出现x的位置,这很容易在O(26 * n)的复杂度内解决。这样每次状态转移只需要常数时间,正常情况下总的复杂度是O(q * 250^3),这肯定会T,但是考虑到每次新加入一个字符需要重新计算的dp值只有250^2个,因此复杂度实际为O(q * 250^2),可以接受。

  1 #include <bits/stdc++.h>
  2
  3 using namespace std;
  4
  5 #define REP(i, n) for (int i = 1; i <= (n); i++)
  6 #define sqr(x) ((x) * (x))
  7
  8 const int maxn = 100000 + 100;
  9 const int maxm = 200000 + 100;
 10 const int maxs = 256;
 11
 12 typedef long long LL;
 13 typedef pair<int, int> pii;
 14 typedef pair<double, double> pdd;
 15
 16 const LL unit = 1LL;
 17 const int INF = 0x3f3f3f3f;
 18 const double eps = 1e-14;
 19 const double inf = 1e15;
 20 const double pi = acos(-1.0);
 21 const int SIZE = 100 + 5;
 22 const LL MOD = 1000000007;
 23
 24 int n, q;
 25 int type;
 26 int Next[maxn][26];
 27 int dp[maxs][maxs][maxs];
 28 string str, opt, word;
 29 string ss[3];
 30
 31 void cal(int a, int b, int c)
 32 {
 33     int &ans = dp[a][b][c];
 34     ans = n;
 35     if (a)
 36         ans = min(ans, Next[dp[a - 1][b][c] + 1][ss[0][a - 1] - ‘a‘]);
 37     if (b)
 38         ans = min(ans, Next[dp[a][b - 1][c] + 1][ss[1][b - 1] - ‘a‘]);
 39     if (c)
 40         ans = min(ans, Next[dp[a][b][c - 1] + 1][ss[2][c - 1] - ‘a‘]);
 41 }
 42
 43 void premanagement()
 44 {
 45     for (int i = 0; i < 26; i++)
 46     {
 47         Next[n][i] = Next[n + 1][i] = n;
 48     }
 49     for (int i = n - 1; i >= 0; i--)
 50     {
 51         int tmp = str[i] - ‘a‘;
 52         for (int j = 0; j < 26; j++)
 53         {
 54             if (j != tmp)
 55                 Next[i][j] = Next[i + 1][j];
 56             else
 57                 Next[i][j] = i;
 58         }
 59     }
 60 }
 61
 62 int main()
 63 {
 64     ios::sync_with_stdio(false);
 65     cin.tie(0);
 66     //freopen("input.txt", "r", stdin);
 67     //freopen("output.txt", "w", stdout);
 68
 69     cin >> n >> q;
 70     cin >> str;
 71     premanagement();
 72     dp[0][0][0] = -1;
 73     for (int i = 0; i < q; i++)
 74     {
 75         cin >> opt >> type;
 76         type--;
 77         if (opt[0] == ‘+‘)
 78         {
 79             cin >> word;
 80             ss[type] += word[0];
 81             int max0 = ss[0].size(), max1 = ss[1].size(), max2 = ss[2].size();
 82             int min0 = (type == 0 ? max0 : 0);
 83             int min1 = (type == 1 ? max1 : 0);
 84             int min2 = (type == 2 ? max2 : 0);
 85             for (int a = min0; a <= max0; a++)
 86             {
 87                 for (int b = min1; b <= max1; b++)
 88                 {
 89                     for (int c = min2; c <= max2; c++)
 90                     {
 91                         cal(a, b, c);
 92                     }
 93                 }
 94             }
 95         }
 96         else
 97         {
 98             ss[type].pop_back();
 99         }
100
101         if (dp[ss[0].size()][ss[1].size()][ss[2].size()] < n)
102         {
103             cout << "YES" << endl;
104         }
105         else
106         {
107             cout << "NO" << endl;
108         }
109     }
110     return 0;
111 }

原文地址:https://www.cnblogs.com/npugen/p/10798295.html

时间: 2024-10-08 03:06:46

Codeforces Round #556 (Div. 2) - D. Three Religions(动态规划)的相关文章

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

Problem  Codeforces Round #556 (Div. 2) - D. Three Religions Time Limit: 1000 mSec Problem Description Input Output Sample Input 51 2 1 2 1 Sample Output 1 1 1 2 2 题解:这个题有做慢了,这种题做慢了和没做出来区别不大... 读题的时候脑子里还意识到素数除了2都是奇数,读完之后就脑子里就只剩欧拉筛了,贪心地构造使得前缀和是连续的素数,那

Codeforces Round #556 (Div. 2)

没想到平成年代最后一场cf居然是手速场,幸好拿了个小号娱乐不然掉分预定 (逃 A: 傻题. 1 /* basic header */ 2 #include <iostream> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <string> 6 #include <cstring> 7 #include <cmath> 8 #include <cstdint> 9

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

题目大意让你改变数组的排序,使前缀和的素数最多: 这是一道模拟题,让你通过判断1和2的个数来解决, 只要特判一下1的个数是零的时候,2的个数是零的时候,或者1只有一个而2的个数又不是0个的时候,剩下的情况我们只有把1的个数分奇数和偶数来考虑,大致思路是这样,接下来就看代码吧 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std

Codeforces Round #428 (Div. 2)

Codeforces Round #428 (Div. 2) A    看懂题目意思就知道做了 #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b; i>=a; --i

Codeforces Round #424 (Div. 2) D. Office Keys(dp)

题目链接:Codeforces Round #424 (Div. 2) D. Office Keys 题意: 在一条轴上有n个人,和m个钥匙,门在s位置. 现在每个人走单位距离需要单位时间. 每个钥匙只能被一个人拿. 求全部的人拿到钥匙并且走到门的最短时间. 题解: 显然没有交叉的情况,因为如果交叉的话可能不是最优解. 然后考虑dp[i][j]表示第i个人拿了第j把钥匙,然后 dp[i][j]=max(val(i,j),min(dp[i-1][i-1~j]))   val(i,j)表示第i个人拿

Codeforces Round #424 (Div. 2) C. Jury Marks(乱搞)

题目链接:Codeforces Round #424 (Div. 2) C. Jury Marks 题意: 给你一个有n个数序列,现在让你确定一个x,使得x通过挨着加这个序列的每一个数能出现所有给出的k个数. 问合法的x有多少个.题目保证这k个数完全不同. 题解: 显然,要将这n个数求一下前缀和,并且排一下序,这样,能出现的数就可以表示为x+a,x+b,x+c了. 这里 x+a,x+b,x+c是递增的.这里我把这个序列叫做A序列 然后对于给出的k个数,我们也排一下序,这里我把它叫做B序列,如果我

[Codeforces] Round #352 (Div. 2)

人生不止眼前的狗血,还有远方的狗带 A题B题一如既往的丝帛题 A题题意:询问按照12345678910111213...的顺序排列下去第n(n<=10^3)个数是多少 题解:打表,输出 1 #include<bits/stdc++.h> 2 using namespace std; 3 int dig[10],A[1005]; 4 int main(){ 5 int aa=0; 6 for(int i=1;;i++){ 7 int x=i,dd=0; 8 while(x)dig[++dd

Codeforces Round #273 (Div. 2)

Codeforces Round #273 (Div. 2) 题目链接 A:签到,仅仅要推断总和是不是5的倍数就可以,注意推断0的情况 B:最大值的情况是每一个集合先放1个,剩下都丢到一个集合去,最小值是尽量平均去分 C:假如3种球从小到大是a, b, c,那么假设(a + b) 2 <= c这个比較明显答案就是a + b了.由于c肯定要剩余了,假设(a + b)2 > c的话,就肯定能构造出最优的(a + b + c) / 3,由于肯定能够先拿a和b去消除c,而且控制a和b成2倍关系或者消除

Codeforces Round #339 (Div. 2) B. Gena&#39;s Code

B. Gena's Code It's the year 4527 and the tanks game that we all know and love still exists. There also exists Great Gena's code, written in 2016. The problem this code solves is: given the number of tanks that go into the battle from each country, f