bzoj 4922(背包dp)

传送门
题解:一个’(”)’串合法当且仅当,任意位置左括号个数前缀和-右括号个数前缀和不小于0且末尾的左括号个数前缀和=右括号个数前缀和。用这个sum正向逆向各做一次01背包,最后存在一对dp值不小于0,则可以将两个子串匹配为一个整串

主要是新学一种01背包的用途,代码实现细节太狗血了。。。打了’?’都是不太清楚但是又不得不这样写的地方orz
P.S.这种写法比网上另一种写法快7倍,内存也省了非常多,简直玄学。。。
这里写图片描述

#include<bits/stdc++.h>
using namespace std;
const int MAXN=305,INF=0x3f3f3f3f;
int n;
char ss[MAXN][MAXN];
int sum[MAXN],mn1[MAXN],mn2[MAXN];
struct NODE {
    int x,num,len;
    friend bool operator <(const NODE &p,const NODE &q) {
        return p.x>q.x;
    }
}a[MAXN],b[MAXN];
int t1=0,t2=0;
int dp1[MAXN*MAXN],dp2[MAXN*MAXN];
int main() {
//  freopen("bzoj 4922.in","r",stdin);
    scanf("%d",&n);
    memset(dp1,128,sizeof(dp1));//???
    memset(dp2,128,sizeof(dp2)); 
    for (int i=1;i<=n;++i) {
        scanf("%s",ss[i]+1);
        int L=strlen(ss[i]+1),k=0;
        for (int j=1;j<=L;++j) {
            sum[i]+=ss[i][j]=='('?1:-1;
            mn1[i]=min(mn1[i],sum[i]);
        }
        for (int j=L;j;--j) {
            k+=ss[i][j]==')'?1:-1;
            mn2[i]=min(mn2[i],k);
        }
        sum[i]>=0?a[++t1]=(NODE){mn1[i],sum[i],L}:b[++t2]=(NODE){mn2[i],-sum[i],L};
    }
    sort(a+1,a+t1+1);
    sort(b+1,b+t2+1);
    dp1[0]=dp2[0]=0;
    for (int i=1;i<=t1;++i)
        for (int j=i*MAXN;j>=a[i].num-a[i].x;--j)
        //一些串中间某位置sum小于0为非法转移,所以j>=a[i].num-a[i].x
            if (j-a[i].num>=0) dp1[j]=max(dp1[j],dp1[j-a[i].num]+a[i].len);
    for (int i=1;i<=t2;++i)
        for (int j=i*MAXN;j>=b[i].num-b[i].x;--j)
            if (j-b[i].num>=0) dp2[j]=max(dp2[j],dp2[j-b[i].num]+b[i].len);
    int ans=0;
    for (int i=MAXN*MAXN;~i;--i)//MAXN--AC?n--WA?
        if (dp1[i]>=0&&dp2[i]>=0) ans=max(ans,dp1[i]+dp2[i]);
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值