2020NYIST个人积分赛第三场 F(正逆哈希+区间dp)

演队在口试中非常不幸。在42道考题中,他恰好没有准备最后一道题,而刚好被问到的正是那道题。演队坐在教授面前,一句话也说不出来。但教授心情很好,给了演队最后一次通过考试的机会。他让这个可怜的学生说出考试要考的科目。不幸的是,演队想不起这个科目名字,尽管他记得科目里有诸如安全、程序、设备、可能还有信息学……

为了准备复试,演队决定记住这门课的名字。为了更好地记住那根长字符串,他决定把它分解成回文,并分别学习每个回文。当然,分解过程中的回文数必须尽可能少。

输入:

输入一行字符串表示为这门课的名字。这是由小写英文字母组成的非空行。这一行的长度最多是4000个字符。

输出:

第一行输出可以分解科目名称的最小的回文字符串数目。在第二行输出回文所有的回文字符串,由空格分隔。如果有几个答案是可能的,输出其中任何一个。

样例:

Input

pasoib
Output
6
p a s o i b

Input
zzzqxx

Output
3
zzz q xx

扫描二维码关注公众号,回复: 10651936 查看本文章

Input
wasitacatisaw

Output
1
wasitacatisaw

思路:

参考lmz的代码,感觉思路很好,枚举正哈希区间(i,j)和逆哈希区间和(n-j+1,n-i+1)区间中的回文序列,再进行递推记录下标,输出即可。
动态转移方程 dp[i]=min(dp[j-1]+1,dp[i]),dp[i]代表从1-i区间的回文序列数量,通过正逆哈希可判断得当前区间中的回文序列数量,然后执行动态转移方程即可

参考代码:

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f3f
typedef unsigned long long ll;
const ll base=13331;
const ll maxn=1e5+5;
ll dp[maxn];//从1--i中回文串的最少个数
ll h1[maxn],h2[maxn],p[maxn],n;
ll pre[maxn];
char s[maxn];
string str[maxn];
ll get1(ll l,ll r)
{
    return h1[r]-h1[l-1]*p[r-l+1];
}
ll get2(ll l,ll r)
{
    return h2[r]-h2[l-1]*p[r-l+1];
}
bool check(ll i,ll j)
{
    if(get1(i,j)==get2(n-j+1,n-i+1))
        return true;
    return false;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    memset(dp,inf,sizeof dp);
    dp[0]=0;
    cin>>(s+1);
    n=strlen(s+1);
    p[0]=1;
    for(ll i=1; i<=n; i++)
    {
        h1[i]=h1[i-1]*base-s[i]-'a'+1;
        h2[i]=h2[i-1]*base-s[n+1-i]-'a'+1;
        p[i]=p[i-1]*base;
    }
    for(ll i=1; i<=n; i++)
    {
        for(ll j=1; j<=i; j++)
        {
            if(check(j,i))
            {
                if(dp[i]>(dp[j-1]+1))
                {
                    pre[i]=j;
                    dp[i]=dp[j-1]+1;
                }
            }
        }
    }
    cout<<dp[n]<<endl;
    int id=0;
    int now=n;
    while(now)
    {
        //cout<<now<<endl;
        for(int i=pre[now]; i<=now; i++)
            str[id]+=s[i];
        now=pre[now]-1;
        id++;
    }
    for(int i=id-1; i>=0; i--)
    {
        if(i!=0)
        cout<<str[i]<<' ';
        else
        cout<<str[i]<<endl;
    }
}
发布了254 篇原创文章 · 获赞 25 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/yangzijiangac/article/details/105338897