Solution S o l u t i o n
考虑在回文自动机上DP
fu
f
u
表示回文自动机中
u
u
节点所代表的回文串最少需要几次才能得到
- 为奇数,
fu=lenu
f
u
=
l
e
n
u
。
- lenu l e n u 为偶数, fu=min(fp+1,fhalfu+(lenu2−lenhalfu)+1) f u = min ( f p + 1 , f h a l f u + ( l e n u 2 − l e n h a l f u ) + 1 )
#include <bits/stdc++.h> using namespace std; const int N = 233333; int test, n; char chr[N]; int s[N]; int ch[N][10]; int par[N], len[N]; int rgt[N], half[N], f[N]; int last, tcnt; inline void init(void) { for (int i = 0; i <= tcnt; i++) { half[i] = 0; for (int j = 0; j < 5; j++) ch[i][j] = 0; } par[0] = par[1] = 1; half[0] = half[1] = 1; len[1] = -1; f[0] = 1; f[1] = -1; tcnt = 1; last = 0; } inline void extend(int pos) { int p = last, key = s[pos]; while (s[pos - len[p] - 1] != key) p = par[p]; if (!ch[p][key]) { int np = ++tcnt, q = par[p]; len[np] = len[p] + 2; while (s[pos - len[q] - 1] != key) q = par[q]; par[np] = ch[q][key]; q = half[p]; while (len[ch[q][key]] > len[np] / 2 || s[pos - len[q] - 1] != key) q = par[q]; half[np] = ch[q][key]; if (len[np] & 1) { f[np] = len[np]; } else { f[np] = min(f[p] + 1, f[half[np]] + len[np] / 2 - len[half[np]] + 1); } ch[p][key] = np; } last = ch[p][key]; } int main(void) { freopen("1.in", "r", stdin); freopen("1.out", "w", stdout); scanf("%d\n", &test); while (test--) { scanf("%s", chr + 1); n = strlen(chr + 1); for (int i = 1; i <= n; i++) if (chr[i] == 'A') s[i] = 1; else if (chr[i] == 'T') s[i] = 2; else if (chr[i] == 'G') s[i] = 3; else if (chr[i] == 'C') s[i] = 4; init(); int ans = 1 << 30; for (int i = 1; i <= n; i++) { extend(i); ans = min(f[last] + n - len[last], ans); } cout << ans << endl; } return 0; }