题目链接:https://qduoj.com/problem/205点击打开链接
Description
在2.14(情人节)的午夜,kkun作为一只程序猿并不难过,并且向单身狗julyc发动了嘲讽技能:
julyc非常伤心,因为作为一只咸鱼直到年前都没有做完boss的任务,所以也没有时间去找学妹加强交流,因此他决定向各位请求帮助,而对于帮助julyc解决问题的小伙伴julyc就会偷偷告诉他们学姐cfenglv的qq啦。。
回文串划分就是将一个字符串划分为若干字串,并且每个字串都是一个回文串。
例如,字符串“ABACABA”可以有几种不同的划分方式,例如{"A","B","A","C","A","B","A"}, {"A","BACAB","A"}, {"ABA","C","ABA"}, or {"ABACABA"}。
julyc的任务是将给定字符串,确定其得到最少子串数量的回文串划分方式的子串数量。
Input
输入第一行包含一个整数T(T<=40),代表测试数据组数。每组测试数据中包含一个只包含大写字母的非空字符串s(length(s)<=1000)
Output
对于每组测试数据,你们应该输出测试数据组数跟答案。每组输出占一行。
Hint
对于第三个样例,最少子串数的分割方案为:“QWERTYTREWQ”,“W”,“E”,“R”,“T”,分成了五个回文串
对于第四个样例,最少子串数的分割方案为:“ABA”,“CCC”,分成了两个回文串
一开始时候的想法是取头尾两个指针 然后判断lcp贪心取最大
然后一直wa到结束。。
最后找出样例
abaaab
很明显如果贪心取最大结果会是3而实际上是2
用dp【i】表示取到第i位的时候回文分割的最小值
这个复杂度是nlogn
然后判断回文的时候 不能用传统的暴力判断 会T
用后缀数组预处理可以减少最内层判断回文的循环降低复杂度
#include <stdio.h>
#include <algorithm>
#include <iostream>
#include <string.h>
#include <math.h>
using namespace std;
#define maxn 22222
int n;
char s[maxn];
int c[maxn],sa[maxn],x[maxn],y[maxn],height[maxn],rrank[maxn],st[maxn][20];
void SA(int m)
{
for(int i=0;i<m;i++)
c[i]=0;
for(int i=0;i<n;i++)
c[x[i]=s[i]]++;
for(int i=1;i<m;i++)
c[i]+=c[i-1];
for(int i=n-1;i>=0;i--)
sa[--c[x[i]]]=i;
for(int k=1;k<=n;k<<=1)
{
int p=0;
for(int i=n-k;i<n;i++)
y[p++]=i;
for(int i=0;i<n;i++)
if(sa[i]>=k)
y[p++]=sa[i]-k;
for(int i=0;i<m;i++)
c[i]=0;
for(int i=0;i<n;i++)
c[x[y[i]]]++;
for(int i=1;i<m;i++)
c[i]+=c[i-1];
for(int i=n-1;i>=0;i--)
sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1;
x[sa[0]]=0;
for(int i=1;i<n;i++)
x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
if(p>=n)
break;
m=p;
}
}
void getheight()
{
int k=0;
for(int i=0;i<=n;i++)
rrank[sa[i]]=i;
for(int i=0;i<n;i++)
{
if(k)
k--;
int j=sa[rrank[i]-1];
while(s[i+k]==s[j+k])
k++;
height[rrank[i]]=k;
}
}
void ST()
{
for(int i=1;i<=n;i++)
st[i][0]=height[i];
for(int j=1;j<=19;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
int getmin(int x,int y)
{
int l=rrank[x];
int r=rrank[y];
if(l>r)
swap(l,r);
l++;
int k=log2(r-l+1);
return min(st[l][k],st[r-(1<<k)+1][k]);
}
int judge(int l,int r,int len)
{
if(getmin(l,2*len-r)>=(r-l+1)/2)
return 1;
return 0;
}
char ss[maxn];
int dp[1111];
int main()
{
int t;
scanf("%d",&t);
for(int cnt=1;cnt<=t;cnt++)
{
scanf(" %s",ss);
n=0;
int len=strlen(ss);
for(int i=0;i<len;i++)
{
s[n++]=ss[i];
}
s[n++]='#';
for(int i=len-1;i>=0;i--)
{
s[n++]=ss[i];
}
s[n++]='\0';
SA(300);
n--;
getheight();
ST();
int n=strlen(ss);
for(int i=0;i<len;i++)
{
dp[i]=i+1;
for(int j=0;j<=i;j++)
{
if(judge(j,i,len))
dp[i]=min(dp[j-1]+1,dp[i]);
}
}
printf("Case %d: %d\n",cnt,dp[n-1]);
}
}