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(i−g(k),j−1)

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

显然还是过不去

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

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

时间复杂度降为O(L*K*N*log\sum Li)O(L∗K∗N∗log∑Li)

/**************************************************************
    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\n",a)
#define ptlld(a) printf("%I64d\n",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");
    }
}
时间: 2024-08-08 16:51:05

hdu 5677 ztr loves substring 二维费用背包+回文的相关文章

HDU 5677 ztr loves substring

Manacher+二维费用多重背包 二进制优化 这题是一眼标算....先计算出每个长度的回文串有几种,然后用二维费用的多重背包判断是否有解. 多重背包做的时候需要二进制优化. #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int maxn = 300; int N, p[maxn]; char str[maxn

hdu 5677 ztr loves substring(manacher,背包问题)

1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 5 /** 6 7 8 manacher 处理出回文串长度 9 p[i]:半径 10 11 if(s[i] == '#' && p[i] == 1) continue; 12 else{ 13 int tmp = p[i] / 2; 14 if(s[i] == '#') for(int i = 2 ; i <= tmp ;

洛谷 P1509 找啊找啊找GF(复习二维费用背包)

传送门 题目背景 "找啊找啊找GF,找到一个好GF,吃顿饭啊拉拉手,你是我的好GF.再见." "诶,别再见啊..." 七夕...七夕...七夕这个日子,对于sqybi这种单身的菜鸟来说是多么的痛苦...虽然他听着这首叫做"找啊找啊找GF"的歌,他还是很痛苦.为了避免这种痛苦,sqybi决定要给自己找点事情干.他去找到了七夕模拟赛的负责人zmc MM,让她给自己一个出题的任务.经过几天的死缠烂打,zmc MM终于同意了. 但是,拿到这个任务的sqy

codevs1959拔河比赛(二维费用背包)

1959 拔河比赛 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 一个学校举行拔河比赛,所有的人被分成了两组,每个人必须(且只能够)在其中的一组,要求两个组的人数相差不能超过1,且两个组内的所有人体重加起来尽可能地接近. 输入描述 Input Description 数据的第1行是一个n,表示参加拔河比赛的总人数,n<=100,接下来的n行表示第1到第n个人的体重,每个人的体重都是整数(1<=weight<=450).

POJ2184Cow Exhibition(二维费用背包)

Cow Exhibition Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9067   Accepted: 3441 Description "Fat and docile, big and dumb, they look so stupid, they aren't much fun..." - Cows with Guns by Dana Lyons The cows want to prove to t

HDU2159 二维费用背包

题目链接:FATE 状态转移方程: dp[ren][num] =max(dp[ren-耐久值][num-1]+ 经验值,dp[ren][num]) dp表示:当前忍耐度ren下杀敌数为num的经验值 枚举分别枚举 所有怪物种类.耐久度.杀怪数 最后在从小到达枚举消耗的耐久度即可 #include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <

hdu3496+poj1948(二维费用背包)

Watch The Movie Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 5106    Accepted Submission(s): 1614 Problem Description New semester is coming, and DuoDuo has to go to school tomorrow. She dec

[二维费用背包DP]找啊找啊找GF

题目链接 思考 首先题目一定是背包DP(多读数据范围和题意) 其次一定是 二维费用的背包问题 (人品和金钱) 最后题目要求的是 在泡尽量多的妹子的情况下,花费最少的时间. DP转移方程一定是二维的没错,但是要满足花费最少妹子最多的这个要求就比较难以解决了.不过也不要想这么多,先看看我的分析. 假设在求解过程中如果花X元RMP,Y单位RP可以到Z个MM,那么在泡第i个MM时,发现可以用X-rmb[i]元,Y-rp[i]单位RP泡到的MM数加上这个MM(也就是+1)比原来Z多,就替换它(因为你的原则

分组背包+二维费用背包

题目:https://www.acwing.com/problem/ 分组背包问题描述是共有n组物品,每组物品你只能选一个,求最大价值 1 #include<iostream> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=110; 6 struct node 7 { 8 int v,w; 9 }; 10 node wp[N]; 11 int n,m; 12