cf7D

题目

http://codeforces.com/contest/7/problem/D

题解

先求出每个点的回文串半径。对于当前所在的前缀,若整个前缀回文,那么前半段后半段一定是对称的对吧,于是不用考虑后半段,当前前缀整段的 k 值一定是前半段 k 值加一。这样把每个前缀的 k 值存一下搞搞,没了。

话说 petr 比赛时用哈希乱搞代码贼短跑得贼快,我见到回文串就无脑 manacher。。还是要学习一个。。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, n) for (int i = 0; i < n; ++i) 

char S[5000010];
int res[10000010], cnt[5000010];
bool ok[5000010];

int main() {
  scanf("%s", S);
  int N = strlen(S);

  int l = -1, r = -1;
  rep(z, 2 * N) {
    int i = (z + 1) >> 1;
    int j = z >> 1;
    int p = i >= r ? 0 : min(r - i, res[2 * (l + r) - z]);
    while (i - p - 1 >= 0 && j + p + 1 < N) {
      if (S[i - p - 1] != S[j + p + 1]) break;
      ++p;
    }
    if (j + p > r) {
      r = j + p;
      l = i - p;
    }
    res[z] = p;
  }

  int ans = 1;
  
  cnt[0] = 1;
  ok[0] = true;
  
  for (int i = 1; i < N; ++i) {
    int c1 = i >> 1;
    int c2 = (i & 1 ? c1 : c1 - 1);
    int cid1 = (c1 << 1 | (i & 1));
    assert(c1 >= 0 && c2 >= 0 && cid1 >= 0);
    if (res[cid1] + c1 >= i) {
      cnt[i] = 1;
      ok[i] = true;
      if (ok[c2]) cnt[i] += cnt[c2];
    }
    ans += cnt[i];
  }

  printf("%d\n", ans);
}

猜你喜欢

转载自www.cnblogs.com/arg-53/p/9058546.html