20250824

T1

我们惊奇地发现这题不是直接哈希加一个桶就写完了吗?顺序统计哈希,记录答案。光速打了一个出来,发现空间只有 31.25MB,算了算,好像不会超。

赛后一测发现超时了。map 换成 umap 就过了。map 万恶之源。

#include <bits/stdc++.h>

using namespace std;
using ULL = unsigned long long;

const int kN = 2e5 + 7;
const ULL base = 13331;

int n, ans;
string s; 
ULL has[kN], bpow[kN];
unordered_map<ULL, bool> b;

ULL gethash(int l, int r) {
  return has[r] - has[l - 1] * bpow[r - l + 1];
}

bool check(int x) {
  b.clear(); ULL f = 0;
  for (int i = 1; i + x - 1 <= n; i++) {
    f = gethash(i, i + x - 1);
    if (b.count(f)) return 1; b[f] = 1;
  }
  return 0;
}

int main() {
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  cin >> n >> s, s = " " + s, bpow[0] = 1; 
  for (int i = 1; i <= n; i++) {
    has[i] = has[i - 1] * base + s[i];
    bpow[i] = bpow[i - 1] * base;
  }
  for (int l = 1, r = n, mid; l <= r; ) {
    mid = (l + r) >> 1;
    if (check(mid)) l = mid + 1, ans = mid;
    else r = mid - 1;
  }
  cout << ans;
  
  return 0;
}

T2

这个东西不是我上午刚出的模拟赛的 T4 吗???简直一模一样!

实际上就是考虑到等差加排列的性质:当我们建立一个桶时,如果对于数 \(i\),假设差为 \(d\),如果 \(i-d\) 存在过但 \(i+d\) 还没有出现,那么由于这是个排列,这个数一定在后面出现,那么也就一定是等差序列。因此考虑拿线段树维护一个桶,对于每个 \(i\),只要其左右不回文,那么一定找得到,线段树/树状数组维护哈希即可。


然后写出来了,大样例都过了,赛后一测,0 分???我一看,int len = min(n - a[i], a[i] - 1), Update(a[i]);,哈哈😄!

#include <bits/stdc++.h>
#define ls (p << 1)
#define rs ((p << 1) | 1)

using namespace std;
using ULL = unsigned long long;

const int kN = 5e5 + 7, base = 131;

int T, n, a[kN];
ULL bpow[kN];

struct S {
  ULL has1, has2, len;

  friend S operator + (S a, S b) {
    return {
      a.has1 * bpow[b.len] + b.has1, 
      b.has2 * bpow[a.len] + a.has2, 
      a.len + b.len
    }; 
  }
} seg[kN << 2];

void Build(int l = 1, int r = n, int p = 1) {
  if (l == r) return (void)(seg[p] = {0, 0, 1});
  int mid = (l + r) >> 1;
  Build(l, mid, ls), Build(mid + 1, r, rs);
  seg[p] = seg[ls] + seg[rs];
}

void Update(int x, int l = 1, int r = n, int p = 1) {
  if (l == r) return (void)(seg[p] = {1, 1, 1});
  int mid = (l + r) >> 1;
  if (x <= mid) Update(x, l, mid, ls);
  else Update(x, mid + 1, r, rs);
  seg[p] = seg[ls] + seg[rs];
}

S Query(int s, int t, int l = 1, int r = n, int p = 1) {
  if (s <= l && r <= t) return seg[p];
  int mid = (l + r) >> 1; S res = {0, 0, 0};
  if (s <= mid) res = res + Query(s, t, l, mid, ls);
  if (mid + 1 <= t) res = res + Query(s, t, mid + 1, r, rs);
  return res;
}

void Work() {
  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> a[i];
  }
  Build(1, n, 1);
  for (int i = 1, len = 0; i <= n; i++) {
    len = min(n - a[i], a[i] - 1), Update(a[i]);
    if (len == 0) continue;
    if (Query(a[i] - len, a[i] - 1).has1 != Query(a[i] + 1, a[i] + len).has2) return (void)(cout << "YES\n");
  }
  cout << "NO\n";
}

int main() {
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  bpow[0] = 1;
  for (int i = 1; i < kN; i++) bpow[i] = bpow[i - 1] * base;
  Work();

  return 0;
}

T3

考虑什么时候有无解的情况:一个串的前缀出现过,或者在按字典序建图时出现了环。

前者可以直接使用字典树,后者带一个建图,将串对 trie 建边,具体来讲,对于节点 \(i\),由于字母 \(i\) 要排在在所有儿子中最靠前的那个,因此我们对其他儿子建一条有向边,代表当前字母的优先级比其他儿子高,如果形成了环则无解,答案可以在跑拓扑排序时记录。

#include <bits/stdc++.h>

using namespace std;

const int kN = 1e6 + 7, kM = 2.5e4 + 7;

int n, m, in[kN];
string s[kM];
queue<int> q;
vector<int> g[28], ans;

struct T {
  int ch[27], ed, t;
} a[kN];

int f(int c) {
  return c - 'a';
}

void Insert(string s) {
  int p = 0, k = 0;
  for (int c : s) {
    k = f(c), (a[p].ch[k] == 0) && (a[p].ch[k] = ++m), p = a[p].ch[k], a[p].t++;
  }
  a[p].ed++;
}

bool Find(string s) {
  int p = 0, k = 0;
  for (int c : s) {
    k = f(c);
    if (a[p].ed) return 1;
    p = a[p].ch[k];
  }
  return 0;
}

int main() {
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> s[i], Insert(s[i]);
  }
  for (int i = 1; i <= n; i++) {
    if (Find(s[i])) {
      cout << "nemoguce\n";
      continue;
    }
    ans.clear();
    for (int j = 0; j < 26; j++) g[j].clear(), in[j] = 0;
    int u = 0;
    for (int j = 0; j < s[i].size(); j++) {
      int c = s[i][j] - 'a';
      for (int k = 0; k < 26; k++) {
        if (c == k || !a[u].ch[k]) continue;
        g[c].push_back(k), in[k]++;
      }
      u = a[u].ch[c];
    }
    for (int j = 0; j < 26; j++) {
      if (!in[j]) q.push(j);
    }
    while (q.size()) {
      int u = q.front(); q.pop();
      ans.push_back(u + 'a');
      for (int v : g[u]) {
        if (!--in[v]) q.push(v);
      }
    }
    for (int j = 0; j < 26; j++) {
      if (in[j] > 0) {
        cout << "nemoguce\n";
        goto shit;
      }
    }
    if (ans.size() == 26) for (char x : ans) cout << x;
    else cout << "nemoguce";
    cout << '\n';
    shit:;
  }

  return 0;
}

T4

KMP + DP。

posted @ 2025-08-26 08:41  PikachuQAQ  阅读(7)  评论(0)    收藏  举报