hdu 5677 ztr loves substring 二维费用背包+回文

题目链接: hdu 5677 ztr loves substring

官方题解:

//这部分是错的(首先,对于每一个串i跑一次manancher,令g[i][j]=p[j]-1g[i][j]=p[j]1

这样,g就存储了所有的回文子串的长度

为了方便,把g降到一维表示)

首先,因为字符串长度较小,所以直接二重for循环找就好了,用一个数组 g记录各个回文串的长度

不妨把每一个子串抽象成一个物品

费用为二维的,即{长度,1}

价值是Bool型的

这样就成了一个二维判断可行性费用背包问题

f(i,j)f(i,j)表示当前选出的长度为i,已经选了j个串,这个状态能否达到

f(i,j)=f(i,j)|f(i-g(k),j-1)f(i,j)=f(i,j)f(ig(k),j1)

这样,时间复杂度为O(L*K*N^{2})O(LKN2​​)

显然还是过不去

我们分析,发现其实g是会大量重复的

那么不妨当做多重背包来处理

时间复杂度降为O(L*K*N*logsum Li)O(LKNlogLi)

/**************************************************************
    Problem:hdu 5677
    User: youmi
    Language: C++
    Result: Accepted
    Time:31MS
    Memory:2264K
****************************************************************/
//#pragma comment(linker, "/STACK:1024000000,1024000000")
//#include<bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <stack>
#include <set>
#include <sstream>
#include <cmath>
#include <queue>
#include <deque>
#include <string>
#include <vector>
#define zeros(a) memset(a,0,sizeof(a))
#define ones(a) memset(a,-1,sizeof(a))
#define sc(a) scanf("%d",&a)
#define sc2(a,b) scanf("%d%d",&a,&b)
#define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define scs(a) scanf("%s",a)
#define sclld(a) scanf("%I64d",&a)
#define pt(a) printf("%d
",a)
#define ptlld(a) printf("%I64d
",a)
#define rep0(i,n) for(int i=0;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define rep_1(i,n) for(int i=n;i>=1;i--)
#define rep_0(i,n) for(int i=n-1;i>=0;i--)
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
#define lson (step<<1)
#define rson (lson+1)
#define esp 1e-6
#define oo 0x3fffffff
#define TEST cout<<"*************************"<<endl

using namespace std;
typedef long long ll;

int n,K,L;

const int maxn=200+10;
char s[maxn];
char p[maxn<<1];
int dp2[maxn<<1];
int str[maxn<<1];
int dp[maxn<<1][maxn<<1];
void manacher(int len)
{
    int l=0;
    p[l++]='$';
    p[l++]='#';
    for(int i=0;i<len;i++)
    {
        p[l++]=s[i];
        p[l++]='#';
    }
    p[l]=0;
    int mx=0,id=0;
    for(int i=0;i<l;i++)
    {
        dp2[i]=mx>i?Min(dp2[2*id-i],mx-i):1;
        while(p[dp2[i]+i]==p[i-dp2[i]])
            dp2[i]++;
        if(mx<dp2[i]+i)
        {
            id=i;
            mx=dp2[i]+i;
        }
    }
}
int check(int l,int r)
{
    for(int i=l,j=r;i<=j;i++,j--)
        if(s[i]!=s[j])
            return 0;
    return 1;
}
void zeroone(int len,int num)
{
    for(int i=L;i>=len;i--)
        for(int j=K;j>=num;j--)
            if(dp[i-len][j-num])
                dp[i][j]++;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif
    int T_T;
    scanf("%d",&T_T);
    for(int kase=1;kase<=T_T;kase++)
    {
        sc3(n,K,L);
        zeros(str);
        rep0(i,n)
        {
            scs(s);
            int len=strlen(s);
            /**manacher(len);
            for(int i=2;i<=2*len;i+=2)
                str[dp2[i]-1]++,mx=Max(mx,dp2[i]-1);*/
            for(int i=0;i<len;i++)
                for(int j=i;j<len;j++)
                    if(check(i,j))
                        str[j-i+1]++;
        }
        zeros(dp);//下面就是二维背包了
        dp[0][0]=1;
        for(int i=1;i<=L;i++)
        {
            if(str[i]==0)
                continue;
            int cnt=1;
            while(cnt<str[i])
            {
                zeroone(i*cnt,cnt);
                str[i]-=cnt;
                cnt<<=1;
            }
            zeroone(i*str[i],str[i]);
        }
        puts(dp[L][K]?"True":"False");
    }
}
不为失败找借口,只为成功找方法
原文地址:https://www.cnblogs.com/youmi/p/5453492.html