AtCoder Code festival 2017qualC-D-dp+优化

传送门
题意:
给你一个字符串s,问s最少分成几块,使得每一块在经过组合后都能成为一个回文串。(|s|≤2e5)

Solution:
我们可以转化一下“回文串”这个定义,对于每个字母我们可以把它分别转化到二进制的0-25位,然后如果一段字符串是回文串,那么这段字符串每个字符的异或一定是0或者2的幂,那么这道题就可以用dp做了:f[i]表示前i个字符的被分成的最小段数,转移即为

f[i]=min(f[j]+1)(1j<i,a[j]a[i]=02)(a[i]) f [ i ] = m i n ⁡ ( f [ j ] + 1 ) ( 1 ≤ j < i , a [ j ] a [ i ] = 0 或 2 的 幂 ) ( a [ i ] 为 前 缀 异 或 和 )

但是这样写是n方的,会T掉,那怎么办呢?
记忆化,我们可以存储每一个子串状态的最小段数(子串状态可以用二进制表示),然后转移时枚举2的幂和0即可。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
char s[200010];
int t[200010];
int f[200010];
int minn[(1<<26)+1];
int main()
{
    scanf("%s",s+1);
    for (int i=1;i<=strlen(s+1);i++)
        t[i]=t[i-1],t[i]^=(1<<(s[i]-'a'));
    for (int i=0;i<=(1<<26)-1;i++) minn[i]=1e9;
    minn[0]=0;
    for (int i=1;i<=strlen(s+1);i++)
    {
        f[i]=1e9;
        for (int j=0;j<=25;j++)
            f[i]=min(f[i],minn[t[i]^(1<<j)]+1);
        f[i]=min(f[i],minn[t[i]]+1);
        minn[t[i]]=min(minn[t[i]],f[i]);
    }
    printf("%d",f[strlen(s+1)]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值