P3333 [ZJOI2013]丽洁体

想要一直爱着某物的话,以妖怪之生来说太长了;
想要实现一切梦想的话,以人类之生来说太短了。

写这题的动机只是这两句话= =

简述

原题面:Luogu

给定字符串 \(T,A,B,C\),每个字符串都由一些由空格分隔的单词构成。
求至少需要在 \(T\) 中删除多少单词,使得 \(T\) 呈现 \(A\cdots B\cdots C\) 的形式。
保证有解。
\(1\le |T|,|A|,|B|,|C|\le 5\times 10^4\),所有单词长度 \(\le 5\),每种单词出现次数 \(\le 500\)。
1S,512MB。

分析

知识点:哈希,贪心,暴力。

先把所有字符串中的所有单词 Hash 一下。

显然,对于最后保留串中的 \(A\) 和 \(C\),在 \(T\) 中距离越远越好,贪心从 \(T\) 两侧找即可,时间复杂度 \(O(|T|)\)。
再从找到的 \(AC\) 中间找 \(B\),每种单词出现次数 \(\le 500\),暴力枚举 \(B\) 的第一个位置,再贪心的找即可,时间复杂度上界 \(O(500|T|)\)。

总时间复杂度上界是 \(O(500|T|)\),可过。

实现

//知识点:哈希,暴力,贪心 
/*
By:Luckyblock
*/
#include <algorithm>
#include <cctype>
#include <cstdio>
#include <cstring>
#define LL long long
const int kN = 3e5 + 10;
//=============================================================
char t[kN], a[kN], b[kN], c[kN];
int ans, lt, la, lb, lc;
int hast[kN], hasa[kN], hasb[kN], hasc[kN];
//=============================================================
inline int read() {
  int f = 1, w = 0;
  char ch = getchar();
  for (; !isdigit(ch); ch = getchar())
    if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) {
    w = (w << 3) + (w << 1) + (ch ^ '0');
  }
  return f * w;
}
void Chkmax(int &fir_, int sec_) {
  if (sec_ > fir_) fir_ = sec_;
}
void Chkmin(int &fir_, int sec_) {
  if (sec_ < fir_) fir_ = sec_;
}
void Has(char *s_, int *has_, int &l_) {
  int lth = strlen(s_);
  for (int i = 0; i < lth; ++ i) {
    if (s_[i] < 'a' || s_[i] > 'z') continue ;
    if (i == 0 || s_[i - 1] < 'a' || s_[i - 1] > 'z') has_[++ l_] = 0;
    has_[l_] = 27 * has_[l_] + s_[i] - 'a' + 1;
  }
}
void Prepare() {
  gets(t), gets(a), gets(b), gets(c);
  Has(t, hast, lt); 
  Has(a, hasa, la);
  Has(b, hasb, lb); 
  Has(c, hasc, lc);
}
//=============================================================
int main() {
  Prepare();
  int l = 0, r = 0, lth;
  for (l = 1, lth = 1; l <= lt; ++ l) {
    if (hast[l] == hasa[lth]) {
      if (lth == la) {
        ++ l;
        break;
      }
      ++ lth;
      continue;
    }
    ++ ans;
  }
  
  for (r = lt, lth = lc; r >= 1; -- r) {
    if (hast[r] == hasc[lth]) {
      if (lth == 1) {
        -- r;
        break;
      }
      -- lth;
      continue;
    }
    ++ ans;
  }
  
  int mincost = lt;
  for (int i = l; i <= r; ++ i) {
    if (hast[i] != hasb[1]) continue;
    int l = 0, cost = 0;
    for (int j = i; j <= r; ++ j) {
      if (hast[j] == hasb[l + 1]) {
        ++ l;
        if (l == lb) break;
        continue ;
      }
      ++ cost;
    }
    if (l == lb) Chkmin(mincost, cost);
  }
  printf("%d\n", ans + mincost);
  return 0;
}
上一篇:CH4912 Meteors


下一篇:ZJOI2013 K大数查询