题意:
给定一个字符串,问有多少个以K或者F或者C结尾的回文子串。
思路:
马拉车算法,求出len。
利用区间加法获得总和即可。
也就是(直接看代码更容易理解)对于新串在i处“+1”,在i+len[i]+1处“-1”。因为这个区间内的字符都有某个以他为结尾的回文串。
代码:
#include <bits/stdc++.h> #define endl '\n' #define int long long #define pii pair<int, int> #define pll pair<int, int> #define ull unsigned long long using namespace std; const int N = 2e7 + 10; char a[N], b[N]; int p[N]; int n; void init() { int k = 0; b[k++] = '$', b[k++] = '#'; for (int i = 0; i < n; i++) b[k++] = a[i], b[k++] = '#'; b[k++] = '^'; n = k; } void manacher() { int mr = 0, mid; for (int i = 0; i < n; i++) { if (i < mr) p[i] = min(p[mid * 2 - i], mr - i); else p[i] = 1; while (b[i - p[i]] == b[i + p[i]]) p[i]++; if (i + p[i] > mr) { mr = i + p[i]; mid = i; } } } int d[N]; int cnt[128]; void solve() { cin>>n; cin >> a; init(); manacher(); for (int i = 0; i < n; i++) { int L = i, R = i + p[i] - 1; d[L]++; d[R + 1]--; } int pre = 0; for (int i = 0; i <n; i++) { pre += d[i]; cnt[b[i]] += pre; } cout << cnt['k'] << " " << cnt['f'] << " " << cnt['c'] << endl; } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int t = 1; // cin >> t; while (t--) solve(); return 0; }