• 洛谷P4022 熟悉的文章


    题意:给定一个串集合s,每次给定一个串t,询问一个最大的L,使得存在一种划分能把t划分成若干个子串, 其中好的子串总长不小于0.9|t|。好的子串定义为长度不小于L且是s中某一个串的子串。

    解:发现这个L可以二分。如果一个L满足那么小一点的L也满足。考虑如何check。

    可以求最长的总好的子串长度,然后看是否大于0.9。

    这样就能想到DP了。设f[i]表示t[0:i]能划分出的最长好的子串。转移就是考虑第i是否是一个好的子串的结尾。如果是就枚举卡开头,否则就是f[i - 1]。

    这个每个位置都有一个最长能匹配的长度mat[i],然后我们以i结尾的好的子串长度限制就是mat[i] ~ mid。

    我们发现转移过来的两个限制,右边界显然是每次 + 1的,而左边界单调递增。具体来说,如果i结尾的最长匹配是[k, i],那么i - 1结尾的最长匹配不会比[k, i - 1]还短。

    所以用广义SAM搞出来mat,然后二分 + 单调队列优化DP。

    注意开头的时候f[0]是mat[0] >= mid

      1 #include <bits/stdc++.h>
      2 
      3 const int N = 1000010;
      4 const double eps = 1e-8;
      5 
      6 int tr[N][2], fail[N], len[N], tot = 1;
      7 int mat[N], f[N];
      8 int stk[N], top, head;
      9 char str[N];
     10 
     11 inline int Max(const int &a, const int &b) {
     12     return a > b ? a : b;
     13 }
     14 
     15 inline int split(int p, int f) {
     16     int Q = tr[p][f], nQ = ++tot;
     17     len[nQ] = len[p] + 1;
     18     fail[nQ] = fail[Q];
     19     fail[Q] = nQ;
     20     memcpy(tr[nQ], tr[Q], sizeof(tr[Q]));
     21     while(tr[p][f] == Q) {
     22         tr[p][f] = nQ;
     23         p = fail[p];
     24     }
     25     return nQ;
     26 }
     27 
     28 inline int insert(int f, int p) {
     29     if(tr[p][f]) {
     30         int Q = tr[p][f];
     31         if(len[Q] == len[p] + 1) {
     32             return Q;
     33         }
     34         else {
     35             return split(p, f);
     36         }
     37     }
     38     int np = ++tot;
     39     len[np] = len[p] + 1;
     40     while(p && !tr[p][f]) {
     41         tr[p][f] = np;
     42         p = fail[p];
     43     }
     44     if(!p) {
     45         fail[np] = 1;
     46     }
     47     else {
     48         int Q = tr[p][f];
     49         if(len[Q] == len[p] + 1) {
     50             fail[np] = Q;
     51         }
     52         else {
     53             fail[np] = split(p, f);
     54         }
     55     }
     56     return np;
     57 }
     58 
     59 int large[N << 2];
     60 std::bitset<N * 4> tag;
     61 
     62 inline void pushdown(int o) {
     63     if(tag[o]) {
     64         tag.set(o << 1);
     65         tag.set(o << 1 | 1);
     66         large[o << 1] = large[o << 1 | 1] = 0;
     67         tag.reset(o);
     68     }
     69     return;
     70 }
     71 
     72 void change(int p, int v, int l, int r, int o) {
     73     if(l == r) {
     74         tag.reset(o);
     75         large[o] = v;
     76         return;
     77     }
     78     pushdown(o);
     79     int mid = (l + r) >> 1;
     80     if(p <= mid) change(p, v, l, mid, o << 1);
     81     else change(p, v, mid + 1, r, o << 1 | 1);
     82     large[o] = Max(large[o << 1], large[o << 1 | 1]);
     83     return;
     84 }
     85 
     86 int getMax(int L, int R, int l, int r, int o) {
     87     if(L <= l && r <= R) {
     88         return large[o];
     89     }
     90     int mid = (l + r) >> 1, ans = 0;
     91     pushdown(o);
     92     if(L <= mid) ans = getMax(L, R, l, mid, o << 1);
     93     if(mid < R) ans = Max(ans, getMax(L, R, mid + 1, r, o << 1 | 1));
     94     return ans;
     95 }
     96 
     97 int main() {
     98     int n, m;
     99     scanf("%d%d", &n, &m);
    100     for(int i = 1; i <= m; i++) {
    101         scanf("%s", str);
    102         int len = strlen(str), last = 1;
    103         for(int j = 0; j < len; j++) {
    104             last = insert(str[j] - '0', last);
    105         }
    106         memset(str, 0, len * sizeof(char));
    107     }
    108 
    109     for(int A = 1; A <= n; A++) {
    110         scanf("%s", str);
    111         int Len = strlen(str);
    112 
    113         int p = 1, lenth = 0;
    114         for(int i = 0; i < Len; i++) {
    115             int f = str[i] - '0';
    116             while(p && !tr[p][f]) {
    117                 p = fail[p];
    118                 lenth = len[p];
    119             }
    120             if(tr[p][f]) {
    121                 p = tr[p][f];
    122                 lenth++;
    123             }
    124             else {
    125                 p = 1, lenth = 0;
    126             }
    127             mat[i] = lenth;
    128             //printf("mat %d = %d 
    ", i, mat[i]);
    129         }
    130 
    131         int l = 0, r = Len;
    132         while(l < r) {
    133             int mid = (l + r + 1) >> 1;
    134 
    135             f[0] = (mat[0] >= mid); /// ERROR : f[0] = mat[0]
    136             stk[head = top = 1] = 0;
    137             for(int i = 1; i < Len; i++) {
    138                 f[i] = f[i - 1];
    139                 int L = i - mat[i], R = i - mid;
    140                 while(head <= top && f[R] - R >= f[stk[top]] - stk[top]) {
    141                     --top;
    142                 }
    143                 stk[++top] = R;
    144                 while(head < top && stk[head] < L) {
    145                     ++head;
    146                 }
    147                 if(L <= stk[head] && stk[head] <= R) {
    148                     f[i] = Max(f[i], f[stk[head]] + i - stk[head]);
    149                 }
    150             }
    151             //printf("mid = %d  f = %d 
    ", mid, f[Len - 1]);
    152             if(10 * f[Len - 1] >= 9 * Len) {
    153                 l = mid;
    154             }
    155             else {
    156                 r = mid - 1;
    157             }
    158         }
    159         printf("%d
    ", r);
    160         memset(str, 0, Len * sizeof(char));
    161     }
    162 
    163     return 0;
    164 }
    AC代码

    我非常傻,一开始写的是个线段树,没看出来单调性...

  • 相关阅读:
    [LiDAR数据模拟]系列(2) HELIOS的TLS点云模拟流程
    [LiDAR数据模拟]系列(1) HELIOS模拟平台介绍
    [漫谈科研]系列(1) 分享才能进步
    python消息队列snakemq使用总结
    关于modbus rtu一个主站与多个从站通信的一点总结
    关于使用ffmpeg的一些牢骚
    Pyqt5 实时图像滚动
    pyqt5 窗体布局
    PyQt5创建第一个窗体(正规套路)
    pyqt中使用matplotlib绘制动态曲线
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10808652.html
Copyright © 2020-2023  润新知