dp的练习总结(4)

P2466 Sue 的小球

1.对于一个区间 (l,r) ,我们得到了最优解,再往外转移必定是最优的,然后就能将求区间最优转化为子问题递归求解。

2.那么一个一个彩蛋收集,此时 Sue 就有 4 种情况:

  对于 l−1 这个彩蛋, Sue 可以从 l 或 r 过去收集。

  对于 r+1 这个彩蛋, Sue 可以从 l 或 r 过去收集。

代码如下:
 

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1010;
struct node{
    int x,y,v;
    bool operator < (node b) const {
        return x<b.x;
    } 
}a[N];
int n,x0,ans,f[N][N][2];
signed main(){
	cin>>n>>x0;
	a[n+1].x=x0;
    memset(f,0x3f3f3f3f,sizeof(f));
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i].x);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i].y),ans+=a[i].y;
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i].v);
    n++;
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++)
        if(a[i].x==x0){
            f[i][i][0]=f[i][i][1]=0;
            break;
        }
    for(int i=1;i<=n;i++)
        a[i].v+=a[i-1].v;
    for(int i=1;i<=n;i++)
        for(int l=1,r=l+i;r<=n;l++,r++){
            f[l][r][0]=min(f[l+1][r][0]+(a[l+1].x-a[l].x)*(a[l].v+a[n].v-a[r].v),
                            f[l+1][r][1]+(a[r].x-a[l].x)*(a[l].v+a[n].v-a[r].v));
            f[l][r][1]=min(f[l][r-1][0]+(a[r].x-a[l].x)*(a[l-1].v+a[n].v-a[r-1].v),
                            f[l][r-1][1]+(a[r].x-a[r-1].x)*(a[l-1].v+a[n].v-a[r-1].v));
        }
    printf("%.3lf\n",(ans-min(f[1][n][0],f[1][n][1]))/1000.0);
    return 0;
}

P7914 括号序列

1.设 f[l,r] 区间 [l,r] 可以形成多少合法串。根据题目条件得知合法串两边都必须是括号,且左边一定是左括号,右边一定是右括号。

2.第一种 (S)(S) 的情况,直接扫一遍 O(n)O(n)。然后考虑 (A),(SA),(AS)。第一种从 [l+1,r−1] 转移,剩下的扫一遍,从 f[i+1,r−1],f[l+1,i−1] ,其中 s[l+1,i],s[i,r−1] 是 S,转移,复杂度 O(n)。

   最后一种考虑枚举断点,转移方程大概是 f[l,i]×f[j,r],s[i+1,j−1] 是 S。随便前后缀和优化一些也可以做到 O(n)。

但是这样会算重,考虑 (∗∗)()∗(),会在每个断点处算一次,那么根据套路,直接让他在第一个断点被计算。

3.考虑给 dp 加一维状态,f[i,j,0/1] 分别代表能或不能使用最后一种转移,那么 f[l,i,0]×f[j,r,1] 转移即可。

代码如下:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
const int N=5e2+5;
int n,k,dp[N][N][3],d[N];
char s[N];
signed main(){
    scanf("%lld %lld",&n,&k);
    scanf("%s",s+1);
    for(register int i=1;i<=n;i++){
        d[i]=d[i-1];
        if((s[i]=='('||s[i]=='?')&&(s[i+1]==')'||s[i+1]=='?')) dp[i][i+1][0]=1;
        if(s[i]=='('||s[i]==')') d[i]=d[i-1]+1;
    }
    for(register int i=2;i<=n;i++){
        for(register int l=1;l<=n;l++){
            int r=l+i-1;
            if(r>n) break;
            if(r-l>=2&&(s[l]=='('||s[l]=='?')&&(s[r]==')'||s[r]=='?')){
                dp[l][r][0]=((dp[l][r][0]+dp[l+1][r-1][1])%mod+dp[l+1][r-1][0])%mod;
            }
            if(r-l>=2&&((d[r-1]-d[l])==0)&&(s[l]=='('||s[l]=='?')&&(s[r]==')'||s[r]=='?')&&r-l-1<=k){
                dp[l][r][0]=(dp[l][r][0]+((d[r-1]-d[l])==0))%mod;
            }
            if(r-l>=3){
                for(register int p=l;p<r;p++){
                    dp[l][r][1]=((dp[l][p][0]%mod*(dp[p+1][r][0]+dp[p+1][r][1])%mod)%mod+dp[l][r][1])%mod;
                }
            }
            if(r-l>=4&&(s[l]=='('||s[l]=='?')&&(s[r]==')'||s[r]=='?')){
                for(register int p=r-k-1;p<r-1;p++){
                    if(r-p-1<=k) dp[l][r][0]=(dp[l][r][0]+(dp[l+1][p][0]+dp[l+1][p][1])*((d[r-1]-d[p])==0))%mod;
                }
            }
            if(r-l>=4&&(s[l]=='('||s[l]=='?')&&(s[r]==')'||s[r]=='?')){
                for(register int p=l+1;p<=min(l+k,r-1);p++){
                    if(p-l<=k) dp[l][r][0]=(dp[l][r][0]+(dp[p+1][r-1][0]+dp[p+1][r-1][1])*((d[p]-d[l])==0))%mod;
                }
            }
            if(r-l>=2){
                for(register int p=l;p<=min(l+k-1,r);p++){
                    dp[l][r][2]=(dp[l][r][2]+(dp[p+1][r][0]+dp[p+1][r][1])%mod*((d[p]-d[l-1])==0))%mod;
                }
            }
            if(r-l>=4){
                for(register int p=l+1;p<r-1;p++){
                    dp[l][r][1]=(dp[l][r][1]+(dp[l][p][0]%mod*dp[p+1][r][2]%mod)%mod)%mod;
                }
            }
        }
    }
    printf("%lld",(dp[1][n][0]+dp[1][n][1])%mod);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值