• 区间dp复习提高专题



    这是一道非常典型的区间dp

    for(int i=2*n-1;i>=1;i--)
    for(int j=i+1;j<=2*n;j++)
    for(int k=i;k<j;k++)
    f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]+a[i]*a[k+1]*a[j+1]);
    int maxn=0;
    for(int i=1;i<=n;i++)
    maxn=max(f[i][i+n-1],maxn);
    


    这个题就没有枚举中间变量k
    而是向两边扩展的
    对于每个区间终极状态老头不知道在左边还是右边
    于是新加一维
    dp[i][j][0]表示关完区间[i,j]的灯后老头在左边
    反之 在右边

    f[c][c][0]=f[c][c][1]=0;//瞬间被关(初始化)
      for(int l=2;l<=n;l++)
        for(int i=1;i+l-1<=n;i++)
          {
        int j=i+l-1;
        f[i][j][0]=min(f[i+1][j][0]+(a[i+1]-a[i])*(sum[i]+sum[n]-sum[j]),//继续走下去会更快吗?
                   f[i+1][j][1]+(a[j]-a[i])*(sum[i]+sum[n]-sum[j]));//还是从j点折返回来会更快?(此时假设[i+1][j]被关,i亮,从j端点往回赶去关i)
    //要注意的一点是sum[n]-(sum[j]-sum[i])是包括了i这一点的电能的,因为走过来的过程中灯i也会耗电
        f[i][j][1]=min(f[i][j-1][0]+(a[j]-a[i])*(sum[i-1]+sum[n]-sum[j-1]),//同上
                   f[i][j-1][1]+(a[j]-a[j-1])*(sum[i-1]+sum[n]-sum[j-1]));
            }
      int ans=min(f[1][n][0],f[1][n][1]);
    


    这个题和第一个题很类似,都是合并类型
    最大最小就在另开一维数组

    f[i][j][0]=max(f[i][j][0],f[i][k][0]+f[k+1][j][0]+s[j]-s[i-1]);
    f[i][j][1]=min(f[i][j][1],f[i][k][1]+f[k+1][j][1]+s[j]-s[i-1]);
    


    这个题类似之前那个灯泡
    dp[i][j][0]表示走完区间[i,j]最终在i时最大数
    dp[i][j][1]表示走完区间[i,j]最终在i时最小费时
    dp[i][j][2]表示走完区间[i,j]最终在j时最大数
    dp[i][j][3]表示走完区间[i,j]最终在j时最小费时
    我的代码样例都过了但是re了,搞不懂

    #include<bits/stdc++.h>
    using namespace std;
    #define lowbit(x) x&(-x)
    #define ll long long
    const int maxn=205;
    ll n,L;
    ll x[maxn],t[maxn];
    ll dp[maxn][maxn][5];//0-1 2-3
    int main(){
    	cin>>n>>L;
    	for(int i=1;i<=n;i++)cin>>x[i],x[i+n+1]=x[i];x[n+1]=x[2*n+2]=L;
    	for(int i=1;i<=n;i++)cin>>t[i],t[i+n+1]=t[i];t[n+1]=t[2*n+2]=1e9; 
    	for(int i=1;i<=maxn*2;i++)
    	for(int j=1;j<=maxn*2;j++)
    	dp[i][j][1]=dp[i][j][3]=1e8;
    	dp[n+1][n+1][1]=dp[n+1][n+1][3]=dp[2*n+2][2*n+2][1]=dp[2*n+2][2*n+2][3]=0;
    	for(int l=2;l<=n+1;l++){
    		for(int i=1;i+l-1<=n*2+2;i++){
    			ll j=l+i-1;
    			ll t1=dp[i+1][j][1]+(x[i+1]-x[i]>0?x[i+1]-x[i]:x[i+1]-x[i]+L);
    			ll t2=dp[i+1][j][3]+(x[j]-x[i]>0?x[j]-x[i]:x[j]-x[i]+L);
    			ll t3=dp[i][j-1][3]+(x[j]-x[j-1]>0?x[j]-x[j-1]:x[j]-x[j-1]+L);
    			ll t4=dp[i][j-1][1]+(x[j]-x[i]>0?x[j]-x[i]:x[j]-x[i]+L);
    			ll dp1=dp[i+1][j][0]+(t1<=t[i]);
    			ll dp2=dp[i+1][j][2]+(t2<=t[i]);
    			ll dp3=dp[i][j-1][2]+(t3<=t[j]);
    			ll dp4=dp[i][j-1][0]+(t4<=t[j]);
    			if(dp1>dp2)dp[i][j][0]=dp1,dp[i][j][1]=t1;
    			else if(dp1==dp2)dp[i][j][0]=dp1,dp[i][j][1]=min(t1,t2);
    			else dp[i][j][0]=dp2,dp[i][j][1]=t2;
    			if(dp3>dp4)dp[i][j][2]=dp3,dp[i][j][3]=t3;
    			else if(dp3==dp4)dp[i][j][2]=dp3,dp[i][j][3]=min(t3,t4);
    			else dp[i][j][2]=dp4,dp[i][j][3]=t4;
    		}
    	}
    	ll ans=0;
    	for(int i=1;i<=n+1;i++)
    		ans=max(ans,max(dp[i][i+n][0],dp[i][i+n][2]));
    	cout<<ans<<endl;
         return 0;
    }
    
  • 相关阅读:
    连通块问题
    线性数据结构
    NOIP2018总结
    原码反码补码详解
    一些常用的算法技巧总结
    骗分导论
    模板
    模板
    AcWing
    AcWing
  • 原文地址:https://www.cnblogs.com/wzxbeliever/p/15666511.html
Copyright © 2020-2023  润新知