Dane jest
Jedno z najprostszych rozwiązań to proste programowanie dynamiczne.
Przez
const int N = 1100000; int t,n,dp[N]; char s[N]; bool substr_equal(int i1, int i2, int len) { REP(i,len) { if (s[i1+i] != s[i2+i]) return false; } return true; } int main() { scanf("%d",&t); REP(test,t) { scanf("%s",s); n = strlen(s); dp[n/2] = n%2; for (int i=n/2-1; i>=0; --i) { dp[i] = 1; for (int j=i+1; j<=n/2; ++j) { if (substr_equal(i, n-j, j-i)) { dp[i] = max(dp[i], 2 + dp[j]); } } } printf("%d\n", dp[0]); } }
Można je przyspieszyć do
void init_hasz() { pot[0] = 1; REP(i,n) { hasz[i+1] = (hasz[i] + ll(s[i])*pot[i]) % P; pot[i+1] = ll(pot[i])*A % P; } } int get_hasz(int i, int len) { return ll(hasz[i+len] + P - hasz[i]) * pot[n-i] % P; } bool substr_equal(int i1, int i2, int len) { return get_hasz(i1, len) == get_hasz(i2, len); }
Zadanie można rozwiązać, używając algorytmu zachłannego: wystarczy obcinać
ze słowa jak najkrótsze kawałki palindromiczne (czyli najkrótsze prefiksy równe sufiksom).
Jeśli użyjemy haszowania, taki program zadziała w czasie
int i=0, cnt=0, found=1; while (found) { found=0; for (int j=i+1; !found && j<=n/2; ++j) { if (substr_equal(i, n-j, j-i)) { i = j; cnt += 2; found = 1; } } } printf("%d\n", cnt + (i<(n+1)/2));
Dlaczego to rozwiązanie jest poprawne?
Załóżmy, że w optymalnym rozwiązaniu skrajnym kawałkiem palindromicznym jest
Tak więc mamy równość
Jeśli