FZU 2218 Simple String Problem(状压DP)

来源:互联网 发布:淘宝店铺主营在哪设置 编辑:程序博客网 时间:2024/05/24 07:33

题意:给你一个长度为n的字符串,仅包含前k个小写字母,求两段子串A和B,A和B中间没有共用的字母类型,求len(A)*len(B)


的最大值。(n<=2000, k<=16)



思路:状态压缩dp(点击打开链接)

    * n^2的复杂度,求出每个状态( 1<<n )所能达到的最大长度。    * dp,求出字母种类小于等于当前state所能达到的最大值(因为可能包含abc和efg的乘积没有ab和efg的乘积大)     * 枚举求此类abc和不含abc的字母dp的乘积得最大值

第二点非常重要,也是比较容易忘记考虑的。因为dp[state]*dp[state^(1<<k-1)]只是计算包含state的字母和包含state之外所有字母的乘积,而题目只要


求没有共有字母即可,所以dp记录的应该是state所含字母的子集的最大长度,而并不能只是stata状态的最大长度。



代码:

#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int maxn = 2005;char str[maxn];int dp[1<<17];int main(void){    int t, n, k;    cin >> t;    while(t--)    {        memset(dp, 0, sizeof(dp));        scanf("%d%d %s", &n, &k, str);        int len = strlen(str);        for(int i = 0; i < len; i++)        {            int tmp = 0;            for(int j = i; j < len; j++)            {                tmp = tmp | (1<<(str[j]-'a'));                dp[tmp] = max(dp[tmp], j-i+1);            }        }        int up = 1<<k;        int ans = 0;        for(int i = 0; i < up; i++)            for(int j = 0; j < k; j++)                if(i & (1<<j))                    dp[i] = max(dp[i], dp[i^(1<<j)]);        for(int i = 0; i < up; i++)            ans = max(ans, dp[i]*dp[i^(up-1)]);        printf("%d\n", ans);    }    return 0;}


原创粉丝点击