qduoj 来自julyc的新年求助(后缀数组判断回文+dp)

题目链接:https://qduoj.com/problem/205点击打开链接

来自julyc的新年求助

Description

在2.14(情人节)的午夜,kkun作为一只程序猿并不难过,并且向单身狗julyc发动了嘲讽技能:

TIM图片20180214210914.png

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

对于每组测试数据,你们应该输出测试数据组数跟答案。每组输出占一行。

Sample Input 1 

4
AAAA
ABCDEFGH
QWERTYTREWQWERT
ABACCC

Sample Output 1

Case 1: 1
Case 2: 8
Case 3: 5
Case 4: 2

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]);
    }

}



猜你喜欢

转载自blog.csdn.net/xuejye/article/details/79344964