[BZOJ3214][Zjoi2013]丽洁体(hash+贪心)

博客介绍了如何解决BZOJ3214题目,利用hash和贪心策略进行字符串匹配。首先计算每个单词的hash值,然后在文本中寻找目标子序列,通过贪心方法找到最优匹配。在匹配过程中,考虑了单词出现的限制,并详细阐述了时间复杂度为O(|A|+|B|+|C|+cnt|T|)的解决方案。
摘要由CSDN通过智能技术生成

Address

https://www.lydsy.com/JudgeOnline/problem.php?id=3214

Solution

为甚么做此题的人比 K 大数查询少……
首先把每个单词求下 hash ,只需要用 int 即可,不需要取膜。
然后在 T T 中,从左往右贪心匹配,匹配出 T 的一个等于 A A 的子序列,使子序列的右端点最靠左。设这个右端点为 L
同样地,也可以贪心匹配出 T T 的一个等于 C 的子序列,使左端点尽量靠右,为 R R
继续在 (L,R) 内匹配子序列 B B ,使 B 的最左端点 l l 和 最右端点 r 满足 rl r − l 最小。
考虑到同一单词出现的次数 500 ≤ 500 ,可以枚举 B B 的左端点 l 后再贪心匹配出最小的 r r
这样,复杂度就是 O(|A|+|B|+|C|+cnt|T|)
cnt c n t B B 第一个字符在 T (L,R) ( L , R ) 内的出现次数。

Code

注:单词的分隔符不一定是空格,也可能是小写字母以外的其他字符。被这个坑了好久

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
using namespace std;
const int N = 3e5 + 5, INF = 0x3f3f3f3f;
int L, R, nt, na, nb, nc, t[N], a[N], b[N], c[N], ans;
char T[N], A[N], B[N], C[N];
void __hash(char *s, int *rp, int &n, int len) {
    int i;
    For (i, 0, len - 1)
        if (s[i] < 'a' || s[i] > 'z') continue;
        else {
            if (i == 0 || s[i - 1] < 'a' || s[i - 1] > 'z') rp[++n] = 0;
            rp[n] = rp[n] * 27 + s[i] - 'a' + 1;
        }
}
int main() {
    int i, j, th = 1;
    gets(T); gets(A); gets(B); gets(C);
    __hash(T, t, nt, strlen(T));
    __hash(A, a, na, strlen(A));
    __hash(B, b, nb, strlen(B));
    __hash(C, c, nc, strlen(C));
    For (L, 1, nt)
        if (t[L] == a[th]) {
            if (th == na) {L++; break;}
            else th++;
        }
        else ans++;
    th = nc;
    Rof (R, nt, 1)
        if (t[R] == c[th]) {
            if (th == 1) {R--; break;}
            else th--;
        }
        else ans++;
    int minp = INF;
    For (i, L, R) {
        if (t[i] != b[1]) continue;
        th = 0; int mp = 0;
        For (j, i, R)
            if (t[j] == b[th + 1]) {
                th++;
                if (th == nb) break;
            }
            else mp++;
        if (th == nb) minp = min(minp, mp);
    }
    cout << ans + minp << endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值