zoukankan      html  css  js  c++  java
  • [ZJOI 2013]丽洁体

    Description

    题库链接

    给出四个字符串 (T,A,B,C) ,问你至少在 (T) 串中删去几个单词能使得 (T) 串变为 (A?B?C) 的形式,其中 (?) 表示任意多的单词,可以为空。

    (1leq |T|,|A|,|B|,|C|leq 50000)

    Solution

    首先注意到不同的字符串最多有 (O(26^5)) 个。我们可以先把字符串 (hash) ,方便处理。

    其次,容易发现的是对于要满足 (A,C) 串的要求,直接贪心就好了,分别从串前和尾扫一遍。

    我们考虑如何选 (B) 。我们先把 (T) 串中 (A,C) 相关的部分去掉。

    一个显然的 (DP) 是记 (f_{i,j}) 为处理过的 (T) 串前 (i) 位选中了 (B) 串前 (j) 位要删去的最少单词数。但这样转移是 (O(|T||B|)) 的,能拿 (70pts)

    转换思路。

    (f_i) 表示第 (i) 位的字符最晚在 (T) 串的哪个位置出现; (g_i) 表示匹配前 (i) 位最少删除的字符。

    注意到相同的字符最多只有 (500) ,我们可以暴力枚举所有的在 (B) 串中与 (T_i) 相同的位置。这样复杂度为 (O(500|T|))

    当然了,如果用相同的思想,枚举所有的在 (B) 串中与 (T_i) 相同的位置。用线段树优化 (70pts) 是可以做到 (O(500|T|log_2 |B|))

    Code

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 250000, M = 12356630, inf = 2e9;
    
    char T[N+5], A[N+5], B[N+5], C[N+5];
    int t[N+5], a[N+5], b[N+5], c[N+5], tt, ta, tb, tc, L, R, ans;
    int f[N+5], g[N+5];
    vector<int>s[M+5];
    void get(char *ch, int *a, int &tot) {
        int len = 0; char c;
        while ((c = getchar()) != '
    ') ch[++len] = c;
        for (int i = 1, j; i <= len; i = j+1) {
        int sum = 0; j = i;
        while (ch[j] >= 'a' && ch[j] <= 'z') sum = sum*26+ch[j]-'a'+1, ++j;
        a[++tot] = sum;
        }
    }
    void work() {
        get(T, t, tt);
        get(A, a, ta);
        get(B, b, tb);
        get(C, c, tc);
        for (int i = 1, loc = 1; i <= tt; i++) {
        if (t[i] == a[loc]) ++loc;
        else ans++;
        if (loc == ta+1) {L = i+1; break; }
        }
        for (int i = tt, loc = tc; i >= 1; i--) {
        if (t[i] == c[loc]) --loc;
        else ans++;
        if (loc == 0) {R = i-1; break; }
        }
        int sum = inf;
        memset(g, 127/3, sizeof(g));
        for (int i = 1; i <= tb; i++) s[b[i]].push_back(i);
        for (int i = L; i <= R; i++)
        for (int j = s[t[i]].size()-1; j >= 0; j--) {
            int x = s[t[i]][j];
            if (x == 1) f[x] = i, g[x] = 0;
            else if (f[x-1]) f[x] = i, g[x] = g[x-1]+i-f[x-1]-1;
            sum = min(sum, g[tb]);
        }
        printf("%d
    ", sum+ans);
    }
    int main() {work(); return 0; }
  • 相关阅读:
    成长型思维
    Spring Boot 入门详细分析
    我们为什么要学习 Spring Boot
    躲不掉的 lambda 表达式
    Java 并发工具包 | J.U.C
    Java 并发编程整体介绍 | 内含超多干货
    彻底搞懂单例模式如何安全的实现
    atomic 包、synchronized | Java 中线程安全
    AD在更新PCB的时候,每次封装都会改变位置?
    1206封装电容在物料可靠性设计比较低
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8672734.html
Copyright © 2011-2022 走看看