FZU 2218 Simple String Problem(状态压缩DP)

8 篇文章 0 订阅

FZU 2218 Simple String Problem(状态压缩DP)

tags : acm


组队赛时遇到的一道题,最后几分钟才做出来。说实话我做的时候也完全没有底,没想到竟然能一发AC

题意

给定一个长度为n,由字母表前k个字母组成的字符串。取其中的两个子串S2,S2,使得这两个字符串中没有相同的字符,求strlen(S1)*strlen(S2)的最大值。

解析

每个子串都可以得到一个01组成的”状态”,其中1表示子串中存在对应的字母,而0表示不存在。由于k最大为16,所以可以用16位二进制表示所有的状态,这样状态压缩就完成了。

dp[X]为状态X及其”子集“对应的字符串的最大长度。此处的”子集“表示状态 X 中1的位数比 X 少,且满足X&X=0的所有状态。
则所求的答案可以以max(dp[ X ]*dp[ (1 << k) - X]来表示。

总的方向有了,要我们要做到就是求出所有状态X对应的dp[X]。

首先,通过一次基础的dp,我们可以将dp[]数组的值设置为每个状态下子串的最大长度。状态转移方程式见代码。

然后就是标准的状压DP做法,从小到大处理每个状态 X ,我们找到所有前驱状态X,通过状态转移方程式dp[X]=max(dp[X],dp[X'])更新dp[X]的值,从而得到前面所说的dp[]数组,也就能得到所求的最大值了。

代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <algorithm>

using namespace std;
#define ll __int64     

const int maxn = 3000;
const int INF = 1 << 30;

char str[maxn];
int num[maxn];
int dp[66666];
int main()
{
    int T, n, k;
    scanf("%d",&T);
    while (T--)
    {
        memset(dp, 0, sizeof(dp));
        scanf("%d%d",&n,&k);
        getchar();
        scanf("%s",str);
        int maxnx=0;
        for (int i = 0; i < n; i++)
        {
            int num = 0;
            for (int j = i; j < n; j++)
            {
                int x = 1 << (str[j] - 'a');
                num |= x;
                dp[num] = max(dp[num],j-i+1);
            }
        }

        for (int i = 0; i < (1<<k); i++)
        {
            for (int j = 0; j < 16; j++)
            {
                int x = 1 << j ;
                if (x&i)
                    dp[i] = max(dp[i], dp[i - x]);
            }
        }
        int ans = 0;
        for (int i = 1; i < (1<<k); i++)
        {
            ans = max(ans, dp[i] * dp[(1<<k)-1 - i]);
        }
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值