• Gym 100712L Alternating Strings II(单调队列)


    题目链接 Alternating Strings II

    题意是指给出一个长度为n的01串,和一个整数k,要求将这个01串划分为很多子串(切很多刀),使得每个子串长度不超过k,且每个字串不是01交替出现的串(例如01, 10, 101, 010, 101010这些都是01交替出现的串),求最少需要切多少次

    令F[i]代表前i个数所需要切的最少的刀数(从1开始计数),那么有

            F[i]  = min{F[j] | |j + 1, i| <= k 且 [j, i]这个子串不是01交替出现的串} + 1

    这时O(n^2)的思路,足以解决上一个问题Gym 100712D了(n=1000),但是这个题数据n<=100000,所以首先寻求NlogN的方法。

    我们记录以i结尾的且是交替串的最长长度为pre,可以看到在计算f[i]时,有以下几种情况:

    1.s[i] == s[i - 1] 这时候没有以i结尾交替出现的串,重置pre=1,f[i] = min{f[i - k], ..., f[i - 1]} + 1  (初始化f[0] = -1,注意f下标是从1开始计数的)

    2.s[i] != s[i - 1] 这时候pre++,由于最后一个与前一个形成交替串,所以需要比较pre与k的关系:

       1) 若pre >= k 或 pre == i,着说明连续出现的交替串长度>k,或者前i个全是01串,那么此时f[i]只能由f[i - 1]转移(相当于在i-1与i之间切一刀)

       2)否则的话pre + 1这个串([i - pre - 1, i])一定不是交替串,那么此时[i - k, i - pre - 1]这个区间的所有点都可以转移到i【1】(最后pre+1个不是交替串,那么最后pre+1+x个一定也不是),所以有f[i] = min{f[i - k], ..., f[i - pre - 1]} + 1,所以可以使用线段树查询区间最小值,复杂度NlogN
    【1】可以由i转移到j表示在i的后面切一刀,[i + 1, j]这个区间是合法串(非交替串)

     下面是代码:

     1 //#pragma comment(linker, "/STACK:1677721600")
     2 #include <map>
     3 #include <set>
     4 #include <stack>
     5 #include <queue>
     6 #include <cmath>
     7 #include <ctime>
     8 #include <vector>
     9 #include <cstdio>
    10 #include <cctype>
    11 #include <cstring>
    12 #include <cstdlib>
    13 #include <iostream>
    14 #include <algorithm>
    15 using namespace std;
    16 #define INF 0x3f3f3f3f
    17 #define inf (-((LL)1<<40))
    18 #define lson k<<1, L, (L + R)>>1
    19 #define rson k<<1|1,  ((L + R)>>1) + 1, R
    20 #define mem0(a) memset(a,0,sizeof(a))
    21 #define mem1(a) memset(a,-1,sizeof(a))
    22 #define mem(a, b) memset(a, b, sizeof(a))
    23 #define FIN freopen("in.txt", "r", stdin)
    24 #define FOUT freopen("out.txt", "w", stdout)
    25 #define rep(i, a, b) for(int i = a; i <= b; i ++)
    26 #define dec(i, a, b) for(int i = a; i >= b; i --)
    27 
    28 template<class T> T MAX(T a, T b) { return a > b ? a : b; }
    29 template<class T> T MIN(T a, T b) { return a < b ? a : b; }
    30 template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; }
    31 template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b;    }
    32 
    33 //typedef __int64 LL;
    34 typedef long long LL;
    35 const int MAXN = 100000 + 100;
    36 const int MAXM = 110000;
    37 const double eps = 1e-8;
    38 LL MOD = 1000000007;
    39 const double PI = 4.0 * atan(1.0);
    40 
    41 int t, n, k;
    42 char s[MAXN];
    43 
    44 struct SegTree {
    45     int mi[MAXN << 2];
    46 
    47     void update(int k, int L, int R, int p, int v) {
    48         if(L == R) { mi[k] = v; return ; }
    49         if((L + R) / 2 >= p) update(lson, p, v);
    50         else update(rson, p, v);
    51         mi[k] = min(mi[k << 1], mi[k << 1 | 1]);
    52     }
    53 
    54     int query(int k, int L, int R, int l, int r) {
    55         if(l == 0) return -1;
    56         if(R < l || r < L) return INF;
    57         if(l <= L && R <= r) return mi[k];
    58         return min(query(lson, l, r), query(rson, l, r));
    59     }
    60 
    61 }st;
    62 
    63 int main()
    64 {
    65 //    FIN;
    66     while(~scanf("%d", &t)) while(t--) {
    67         scanf("%d %d%*c %s", &n, &k, s);
    68         mem0(st.mi);
    69         st.update(1, 1, n, 1, 0);
    70         int pre = 1, val;
    71         rep (i, 2, n) {
    72             if(s[i - 1] == s[i - 2]) {
    73                 pre = 1;
    74                 val = st.query(1, 1, n, max(i - k, 0), i - 1);
    75             }
    76             else {
    77                 pre ++;
    78                 if(pre >= k || pre == i) val = st.query(1, 1, n, i - 1, i - 1);
    79                 else val = st.query(1, 1, n, max(i - k, 0), i - 1 - pre);
    80             }
    81             st.update(1, 1, n, i, val + 1);
    82         }
    83         cout << st.query(1, 1, n, n, n) << endl;
    84     }
    85     return 0;
    86 }
    View Code

    同时,这道题还有O(N)的方法(想了太久才搞出= =!)

    在上面的过程中讲到,如果i可以由j转移得到,那么一定可以由j - 1转移得到(前提是|j - 1, i| <= k), 那么如果此时f[j - 1] > f[j],那么在计算f[i]时吗,只要j存在,就不可能由j - 1转移(这时显而易见的),所以我们使用队列维护一个f值不降的序列,并记录下标。

    在计算f[i]时,首先将队首与i的区间长度>k的点删掉,然后再根据上面讨论的几种情况判断是根据队首转移还是队尾转移,然后将f[i]入队,再根据f[i]的值维护队列的单调性。

     1 //#pragma comment(linker, "/STACK:1677721600")
     2 #include <map>
     3 #include <set>
     4 #include <stack>
     5 #include <queue>
     6 #include <cmath>
     7 #include <ctime>
     8 #include <vector>
     9 #include <cstdio>
    10 #include <cctype>
    11 #include <cstring>
    12 #include <cstdlib>
    13 #include <iostream>
    14 #include <algorithm>
    15 using namespace std;
    16 #define INF 0x3f3f3f3f
    17 #define inf (-((LL)1<<40))
    18 #define lson k<<1, L, (L + R)>>1
    19 #define rson k<<1|1,  ((L + R)>>1) + 1, R
    20 #define mem0(a) memset(a,0,sizeof(a))
    21 #define mem1(a) memset(a,-1,sizeof(a))
    22 #define mem(a, b) memset(a, b, sizeof(a))
    23 #define FIN freopen("in.txt", "r", stdin)
    24 #define FOUT freopen("out.txt", "w", stdout)
    25 #define rep(i, a, b) for(int i = a; i <= b; i ++)
    26 #define dec(i, a, b) for(int i = a; i >= b; i --)
    27 
    28 template<class T> T MAX(T a, T b) { return a > b ? a : b; }
    29 template<class T> T MIN(T a, T b) { return a < b ? a : b; }
    30 template<class T> T GCD(T a, T b) { return b ? GCD(b, a%b) : a; }
    31 template<class T> T LCM(T a, T b) { return a / GCD(a,b) * b;    }
    32 
    33 //typedef __int64 LL;
    34 typedef long long LL;
    35 const int MAXN = 100000 + 100;
    36 const int MAXM = 110000;
    37 const double eps = 1e-8;
    38 LL MOD = 1000000007;
    39 
    40 const int R = 0;
    41 const int S = 1;
    42 const int P = 2;
    43 
    44 struct Node {
    45     int id, x;
    46     Node(int _id = 0, int _x = 0) {
    47         id = _id; x = _x;
    48     }
    49 }q[MAXN];
    50 int st = 0, ed = 0;
    51 int T, n, k;
    52 char s[MAXN];
    53 
    54 void pop_fr(int i) {
    55     while(st < ed && i - q[st].id > k) st++;
    56 }
    57 
    58 void pop_ed(int id, int val) {
    59     while(st < ed && q[ed - 1].x > val) ed --;
    60     q[ed++] = Node(id, val);
    61 }
    62 
    63 int main()
    64 {
    65 //    FIN;
    66 //    FOUT;
    67     int cas = 0;
    68     while(~scanf("%d", &T)) while(T--) {
    69         scanf("%d %d%*c %s", &n, &k, s);
    70         int len = strlen(s), pre = 1;
    71         int f = 0;
    72         st = ed = 0;
    73         q[ed ++] = Node(0, -1);
    74         q[ed ++] = Node(1, 0);
    75         rep (i, 1, len - 1) {
    76             pop_fr(i + 1);
    77             if(s[i] == s[i - 1]) {
    78                 f = q[st].x + 1;
    79                 pre = 1;
    80             }
    81             else {
    82                 pre ++;
    83                 f = (pre >= (i + 1 - q[st].id) || pre == i + 1) ? (q[ed - 1].x + 1) : (q[st].x + 1);
    84             }
    85             pop_ed(i + 1, f);
    86             //printf("%d: %d
    ", i + 1, f);
    87         }
    88         cout << f << endl;
    89     }
    90     return 0;
    91 }
  • 相关阅读:
    CRC在线计算器
    freemodbus-v1.5.0 源码分析
    图及其实现
    最短路径
    交换排序-------快速排序
    FreeRTOS--删除任务
    Install OE and BitBake
    高端编程之DOM
    timeout使用实例
    使用JS提交表单
  • 原文地址:https://www.cnblogs.com/gj-Acit/p/4662772.html
Copyright © 2020-2023  润新知