zoukankan      html  css  js  c++  java
  • [CF762C] Two Strings(预处理,二分答案)

    题目链接:http://codeforces.com/contest/762/problem/C

    题意:两个字符串a、b。希望在a中删掉连续的字符串,使得b是a的子序列。

    希望删掉的是连续的字符串,那么可以预处理两个数组pre和suf。

    pre(i)表示b[0,i]为a的子序列,a的最短长度。

    suf(i)表示b[i,na)为a的子序列,a倒着数的最短长度。

    会发现这两个数列是单调的,二分答案len,表示中间删掉的字符串长度为len。O(n)枚举a删除的起始点,判断即可。

    注意判断时枚举到起点为0,即无前缀的时候,要判断这时后缀长度是否满足条件。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn = 100100;
     5 char a[maxn], b[maxn];
     6 int na, nb;
     7 int pre[maxn], suf[maxn];
     8 bool exflag;
     9 string ret;
    10 
    11 bool ok(int len) {
    12     for(int i = 0; i <= nb-len; i++) {
    13         if((i == 0 && suf[len] >= 0) || pre[i-1] < suf[i+len]) {
    14             ret = "";
    15             exflag = 1;
    16             for(int j = 0; j < i; j++) ret += b[j];
    17             for(int j = i+len; b[j]; j++) ret += b[j];
    18             return 1;
    19         }
    20     }
    21     return 0;
    22 }
    23 
    24 int main() {
    25     // freopen("in", "r", stdin);
    26     memset(a, 0, sizeof(a));
    27     memset(a, 0, sizeof(b));
    28     while(~scanf("%s%s",a,b)) {
    29         na = strlen(a); nb = strlen(b);
    30         memset(pre, 0, sizeof(pre));
    31         memset(suf, 0, sizeof(suf));
    32         int p = 0;
    33         for(int i = 0; i < nb; i++, p++) {
    34             while(p < na && a[p] != b[i]) p++;
    35             pre[i] = p;
    36         }
    37         p = na - 1;
    38         for(int i = nb-1; i >= 0; i--, p--) {
    39             while(p >= 0 && a[p] != b[i]) p--;
    40             suf[i] = p;
    41         }
    42         suf[nb] = na;
    43         // for(int i = 1; i <= nb; i++) printf("%d ", pre[i]); printf("
    ");
    44         // for(int i = 1; i <= nb; i++) printf("%d ", suf[i]); printf("
    ");
    45         exflag = 0; ret = "";
    46         int lo = 0, hi = nb - 1;
    47         while(lo <= hi) {
    48             int mid = (lo + hi) >> 1;
    49             if(ok(mid)) hi = mid - 1;
    50             else lo = mid + 1;
    51         }
    52         if(!exflag) puts("-");
    53         else cout << ret << endl;
    54         memset(a, 0, sizeof(a));
    55         memset(a, 0, sizeof(b));
    56     }
    57     return 0;
    58 }
  • 相关阅读:
    腾讯//最长回文子串
    腾讯//最长回文子串
    马拉车算法
    马拉车算法
    简单实操_Github创建本地仓库及SSH KEY
    Linux5_磁盘 分区 挂载点的理解
    Linux4_手动分区方案
    Linux3_什么是Uboot
    stdin stdout stderr 标准I/O流
    卢克,学着去读源代码
  • 原文地址:https://www.cnblogs.com/kirai/p/6874482.html
Copyright © 2011-2022 走看看