Codeforces Round #556 (Div. 2) - D. Three Religions(動態規劃)

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

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
- 2c++

Sample Output

YES
YES
YES
YES
YES
YES
NO
YES數組

 

題解:動態規劃,意識到這個題是動態規劃以後難點在於要優化什麼東西,本題是讓判斷原串可否劃分紅題中不斷更新的三個字符串,一般狀況下dp數組不單單記錄true/false這種信息,由於這種信息每每能夠在不改變複雜度的狀況下經過記錄更具體的信息來直接導出,而這些更具體的信息會給狀態的轉移帶來便利,本題就是這樣的狀況。優化

  意識到本題的dp屬於分段決策一樣很重要,對於當前的三個字符串,判斷是否合法的方式是逐個加入字符,逐個加入的過程就是自然的階段,而每一個階段須要作出的決策是加入哪個字符串的字符,在這個過程當中維護的信息就是把第一個串的前 a 個字符,第二個串的前 b 個字符,第三個串的前 c 個字符放進去所須要原串的最小長度。spa

  有了這樣的狀態定義轉移方程天然很簡單,好比考慮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),能夠接受。code

 

  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 }
相關文章
相關標籤/搜索