•题意
•思路一
定义 dp[i] 表示 0~i 的最少划分数;
首先,用马拉车算法求解出回文半径数组;
对于第 i 个字符 si,遍历 j (0 ≤ j < i),判断以 j 为回文中心的最大回文串是否包含 si;
如果包含,dp[ i ]=min{dp[ i ],dp[2*j-i-1]+1};
•Code
View Code1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e3+50; 4 5 char t[maxn]; 6 int r[maxn<<1]; 7 8 struct Manacher 9 { 10 char s[maxn<<1]; 11 void Init(char *ss,int len) 12 { 13 int index=0; 14 s[index++]='#'; 15 for(int i=0;i < len;++i) 16 { 17 s[index++]=ss[i]; 18 s[index++]='#'; 19 } 20 s[index]='\0'; 21 } 22 void mana(char *ss) 23 { 24 Init(ss,strlen(ss)); 25 int len=strlen(s); 26 int R=-1; 27 int C; 28 for(int i=0;i < len;++i) 29 { 30 r[i]=R > i ? min(R-i+1,r[2*C-i]):1; 31 for(;i-r[i] >= 0 && i+r[i] < len && s[i-r[i]] == s[i+r[i]];r[i]++); 32 if(i+r[i] > R) 33 { 34 R=i+r[i]-1; 35 C=i; 36 } 37 } 38 } 39 }_mana; 40 41 int dp[maxn]; 42 int Solve() 43 { 44 _mana.mana(t); 45 46 dp[0]=1; 47 int len=strlen(t); 48 for(int i=1;i < len;++i) 49 { 50 dp[i]=dp[i-1]+1; 51 for(int j=0;j <= 2*i;++j) 52 { 53 54 ///t中的第i个字符在预处理后的s数组中的位置为2*i+1 55 ///因为可能由偶回文的情况,所以需要用到'#' 56 ///直接判断在s数组中j的对应的最大回文j+r[j]是否包含2*i+1 57 ///如果包含,再找到2*i+1以j为中心的对称点2*j-(2*i+1) 58 ///判断2*j-(2*i+1)对应于t中的位置的前一个位置(2*j-(2*i+1))/2-1是否在[0,len-1]范围内 59 ///如果在,更新dp[i] 60 int cur=j+r[j]; 61 int index=(2*j-2*i-1)/2-1; 62 if(2*i+1 < cur) 63 dp[i]=min(dp[i],1+(index >= 0 ? dp[index]:0)); 64 } 65 } 66 return dp[len-1]; 67 } 68 int main() 69 { 70 // freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin); 71 int test; 72 scanf("%d",&test); 73 while(test--) 74 { 75 scanf("%s",t); 76 printf("%d\n",Solve()); 77 } 78 return 0; 79 }