d[i]表示前面i個字符劃分紅的最小回文串個數,ios
轉移:當第i字符加進來和前面區間j構成迴文串,那麼d[i] = d[j]+1。算法
要判斷前面的字符j+1到i是否是迴文串,能夠用Manacher算法預處理出來。(其實O(n^2)判斷迴文串的也能夠,時間複雜度不會變,只是爲了學習Manacher數組
Manacher最奇妙的地方在於用'#'把奇偶串的問題合併到了一塊兒以及利用對稱性快速計算P數組學習
#include <iostream> #include <algorithm> #include <cstring> #include<cstdio> using namespace std; const int MAX = 1042; int len, p[2*MAX]; char str[MAX], newstr[2*MAX]; bool isPal[MAX][MAX]; void change() { int i; newstr[0] = '@'; newstr[1] = '#'; for (i = 0; i < len; i++){ newstr[2*i + 2] = str[i]; newstr[2*i + 3] = '#'; } newstr[2*len + 2] = '\0'; return ; } #define toPre(x) ((x-1)>>1) void Manacher() { int i, j, id, maxid = 0; len = 2 * len + 2; for (i = 0; i < len; i++){ if (maxid > i){ p[i] = min(p[2*id - i], maxid - i);//利用對稱性快速計算p數組 } else{ p[i] = 1; } while (newstr[i+p[i]] == newstr[i-p[i]]) p[i]++; if (p[i] + i > maxid){ maxid = p[i] + i; id = i; } } for( i = 1; i < len; i++){ char pivot = newstr[i]; p[i]--; for(j = !(pivot<='z'&&pivot>='a'); j < p[i]; j+=2){ int u = toPre(i-j),v = toPre(i+j); isPal[u][v] = true; } } } int d[MAX]; int main() { //freopen("in.txt","r",stdin); int T; scanf("%d",&T); while (T--){ scanf("%s",str); len = strlen(str); change(); memset(isPal,0,sizeof(isPal)); Manacher(); len = (len-1)>>1; for(int i = 0; i < len; i++){ d[i] = isPal[0][i]?1:i+1; for(int j = 0; j < i; j++)if(isPal[j+1][i]){ d[i] = min(d[i],d[j]+1); } } printf("%d\n",d[len-1]); } // system("pause"); return 0; }