阿福最近对回文串产生了非常浓厚的兴趣。

如果一个字符串从左往右看和从右往左看完全相同的话,那么就认为这个串是一个回文串。例如,“abcaacba”是一个回文串,“abcaaba”则不是一个回文串。

阿福现在强迫症发作,看到什么字符串都想要把它变成回文的。阿福可以通过切割字符串,使得切割完之后得到的子串都是回文的。

现在阿福想知道他最少切割多少次就可以达到目的。例如,对于字符串“abaacca”,最少切割一次,就可以得到“aba”和“acca”这两个回文子串。

Input

输入的第一行是一个整数 T (T <= 20) ,表示一共有 T 组数据。 
接下来的 T 行,每一行都包含了一个长度不超过的 1000 的字符串,且字符串只包含了小写字母。

Output

对于每组数据,输出一行。该行包含一个整数,表示阿福最少切割的次数,使得切割完得到的子串都是回文的。

Sample Input

3
abaacca
abcd
abcba

Sample Output

1
3
0

Hint

对于第一组样例,阿福最少切割 1 次,将原串切割为“aba”和“acca”两个回文子串。 
对于第二组样例,阿福最少切割 3 次,将原串切割为“a”、“b”、“c”、“d”这四个回文子串。 
对于第三组样例,阿福不需要切割,原串本身就是一个回文串。


题目思路:

可以考虑一维dp ,表示 前i个字符 已经划分完之后 最小的划分次数  

那么 dp[i]的话就有好几种选择,在第一个字符后面划一下,或者第二个字符后划一下,.....第i个字符后划一下

我们如果在第k个字符后面划一刀 那么[k+1,i]必须是回文才可以

那么我们考虑一个字符串:abaa

dp[1]=0 ;因为一个字符绝对是回文

dp[2]我们考虑可以在第一个字符后划一下,那么 ab子串需要划一下

dp[3]这里要特别注意,因为aba是回文字符串 ,所以这个地方还可以从第0个字符直接开始,此时不需要划一下,dp[3]=0;

dp[4]可以在0,1,2,3位置后划一下,可在0后面[1,4]不是回文,不满足题意 [2,4]也不满足题意 [3,4]是回文,所以dp[4]可以等于dp[2]+1=2,[4,4]是回文,所以dp[4]=dp[3]+1=1 所以dp[4]=1;

具体状态转移方程+特判看代码:

/***
Accepted
Time
13ms
Memory
128kB
Length
923
Lang
G++(4.5)
Submitted
2019-09-27 16:56:34
Shared
****/
Select Code
#include <bits/stdc++.h>
#include<stdio.h>
#include<vector>
#pragma GCC optimize(2)
typedef long long ll;
typedef unsigned long long ull;
const int mod=998244353;
const int maxn=1e5+5;
const ll INF=100000000000005;
using namespace std;
ll n,m;
char str[maxn];
bool judge(int s,int e)
{
    while(s<=e)
    {
        if(str[s]!=str[e]) return false;
        s++;e--;
    }
    return true;
}
ll dp[maxn];
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%s",str+1);
        int len=strlen(str+1);
        for(int i=1;i<=len;i++) dp[i]=INF;
        dp[1]=0;
        for(int i=2;i<=len;i++){
            for(int j=0;j<i;j++)
                if(judge(j+1,i)){
                    if(j==0) dp[i]=min(0ll,dp[i]);
                    else dp[i]=min(dp[j]+1,dp[i]);
                }
        }
        printf("%lld\n",dp[len]);
    }
    return 0;
}

总结:这类题目好像叫做划分dp,第一次做能想到不容易,加油叭.