串简单题泛做

Posted lim-817

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了串简单题泛做相关的知识,希望对你有一定的参考价值。

bzoj 3942: 注意到没有一个串被另一个串完全包含是个很好的性质,如果没有就意味着按顺序匹配的话每匹配到一个就可以直接删掉。

那就维护一个栈来搞当前在哪里,然后直接在ac自动机上匹配即可,匹配掉了就弹掉。

#include <bits/stdc++.h>
#pragma GCC optimize(2)

#define rep(i, l, r) for (int i = (l); i <= (r); ++i)
#define per(i, r, l) for (int i = (r); i >= (l); --i)

using namespace std;

typedef long long ll;
typedef pair <int, int> pii;
typedef vector <int> vi;

int gi() {
  int f = 1, x = 0; char ch = getchar();
  while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
  while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
  return f * x;
}

const int N = 100005;
int tr[N][26], fail[N], e[N], tot, n, pos[N], tp;
char s[N], t[N], st[N];
void Build(char* s) {
  int u = 0; 
  for (int i = 1; s[i]; ++i) {
    if (!tr[u][s[i] - 'a'])
      tr[u][s[i] - 'a'] = ++tot;
    u = tr[u][s[i] - 'a'];
  }
  e[u] = strlen(s + 1); 
}
void Getfail() {
  queue<int> q;
  for (int i = 0; i < 26; ++i)
    if (tr[0][i])
      q.push(tr[0][i]);
  while (!q.empty()) {
    int u = q.front();
    q.pop();
    for (int i = 0; i < 26; ++i) {
      if (tr[u][i])
        fail[tr[u][i]] = tr[fail[u]][i], q.push(tr[u][i]);
      else
        tr[u][i] = tr[fail[u]][i];
    }
  }
}
int main() {
  scanf("%s", t + 1);
  n = gi();
  rep (i, 1, n) {
    scanf ("%s", s + 1);
    Build(s);
  }
  Getfail();
  int m = strlen(t + 1), now = 0;
  st[++tp] = ' ';
  pos[tp] = now; 
  rep (i, 1, m) {
    now = tr[now][t[i] - 'a'];
    pos[++tp] = now;
    st[tp] = t[i];
    if (e[now]) {
      assert(tp >= e[now]);
      tp -= e[now];
      now = pos[tp];
    }
  }
  rep(i, 2, tp) putchar(st[i]);
  return 0;
}

bzoj 4974:

首先用i-per[i]求出fail[i],并钦定第一个字符为a。

如果没跳到头肯定能知道这个字母是啥。如果跳到头了,那就mark一下已经被用过的字符,选一个最小的没被用到的填上。

#include <bits/stdc++.h>
#pragma GCC optimize(2)

#define rep(i, l, r) for (int i = (l); i <= (r); ++i)
#define per(i, r, l) for (int i = (r); i >= (l); --i)

using namespace std;

typedef long long ll;
typedef pair <int, int> pii;
typedef vector <int> vi;

int gi() {
  int f = 1, x = 0; char ch = getchar();
  while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
  while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
  return f * x;
}
const int N = 1000010;
int n, per[N], fail[N], ans[N];
int main() {
  n = gi();
  rep (i, 1, n) per[i] = gi(), fail[i] = i - per[i];
  ans[1] = 0;
  rep (i, 2, n) {
    if (fail[i])
      ans[i] = ans[fail[i]];
    else {
      int pos = fail[i - 1];
      vi used(26); 
      while (true) {
        used[ans[pos + 1]] = 1;
        if (!pos) break;
        pos = fail[pos];
      }
      for (int j = 0; j < 26; ++j) if (!used[j]) {
        ans[i] = j;
        break;
      }
    }
  }
  rep(i, 1, n) putchar(ans[i] + 'a');
  return 0;
}

poj2185

先把每行当做一个字符,把列最小周期求出来,再把列当做一个字符,求行的最小周期即可。

#include <bits/stdc++.h>

#pragma GCC optimize(2)

#define rep(i, l, r) for (int i = (l); i <= (r); ++i)
#define per(i, r, l) for (int i = (r); i >= (l); --i)
using namespace std;

typedef long long ll;
typedef pair <int, int> pii;
typedef vector <int> vi;

int gi() {
    int f = 1, x = 0; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
    return f * x;
}

const int N = 10000 + 5, M = 105; 
char s[N][M];
int n, m, fail[N], sn, sm;
bool same(int l, int r) {
    rep (i, 1, m) if (s[l][i] != s[r][i]) return 0;
    return 1; 
}
bool _same(int l, int r) {
    rep (i, 1, sn) if (s[i][l] != s[i][r]) return 0;
    return 1; 
}
int main() {
    n = gi(), m = gi();
    rep (i, 1, n)
        scanf("%s", s[i] + 1);
    fail[1] = 0; 
    for (int i = 2, j = 0; i <= n; ++i) {
        while (j && !same(j + 1, i)) j = fail[j];
        j += same(j + 1, i);
        fail[i] = j; 
    }
    sn = n - fail[n];
    fail[1] = 0;
    for (int i = 2, j = 0; i <= m; ++i) {
        while (j && !_same(j + 1, i)) j = fail[j];
        j += _same(j + 1, i);
        fail[i] = j;
    }
    sm = m - fail[m];

    cout << sn * sm << endl;
    return 0;
}

以上是关于串简单题泛做的主要内容,如果未能解决你的问题,请参考以下文章

历年NOIP水题泛做

AC自动机+DP泛做

SA 例题泛做 解题报告

SNOI2017(BZOJ5015~5018)泛做

解题报告(十八)Codeforces - 数学题目泛做(难度:2000 ~ 3000 + )

背包DP泛做