codechef - PALIN3

题目

https://www.codechef.com/problems/PALIN3

题解

求出每个位置的最长回文串,偶数长度的回文串找任意一侧三的倍数的段数,奇数长度的找使得 (2 * 段和 + 中心) mod 3 == 0 的段数,"0" 的单独考虑一下。

manacher 忘了更新最大左端点,卡了半天 :)





#include <bits/stdc++.h>

using namespace std;

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

typedef long long i64;

const int MAX = 1000010;

char S[MAX];
int pal[2 * MAX];

int _rem[MAX], _cnt[MAX][3];
int* rem = _rem + 1, (*cnt)[3] = _cnt + 1;

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

  int pfs = 0;
  rep(i, N) {
    int x = S[i] - '0';
    pfs = (pfs + x) % 3;
    rem[i] = pfs;
    rep(j, 3) cnt[i][j] = cnt[i - 1][j];
    cnt[i][pfs] += (S[i] != '0');
  }

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

  i64 ans = 0;
  for (int z = 0; z < 2 * N - 1; z += 2) {
    if (pal[z] == 0) continue;
    int c = z >> 1;
    int t = (S[c] - '0') % 3;
    if (t) t = 3 - t;
    t = (t + rem[c - 1]) % 3;
    ans += cnt[c + pal[z]][t] - cnt[c][t];
  }
  for (int z = 1; z < 2 * N - 1; z += 2) {
    int c = z >> 1;
    int t = rem[c];
    ans += cnt[c + pal[z]][t] - cnt[c][t];
  }
  rep(i, N) ans += (S[i] % 3 == 0);
  printf("%lld\n", ans);
}

猜你喜欢

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