zoukankan      html  css  js  c++  java
  • Codeforces Round #556 (Div. 2)

    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 }
  • 相关阅读:
    设置发光字
    QQ空间无导航条应对方法
    网页设计经典网站欣赏
    页面居中显示
    获取元素的绝对位置
    输入两个整数 n 和 m,从数列1,2,3.......n 中 随意取几个数, 使其和等于 m ,要求将其中所有的可能组合列出来.
    最长重复子字符串
    从头到尾彻底解析Hash 表算法
    求二叉树中节点的最大距离
    MySQL学习笔记——显示数据库信息
  • 原文地址:https://www.cnblogs.com/npugen/p/10798295.html
Copyright © 2011-2022 走看看