密室逃脱 - dp

题目大意:
有n个房间,i和i+1之间有扇门,能被打开当且仅当第i个房间有ai个人按下按钮或者第i+1个房间有bi个人按下按钮。门打开后人可以双向通过。按按钮的人不能移动,一旦放开按钮门就会关死。现在要求你在每个房间放一些人,使得放的总人数最多,并且不存在一种方案使得第1个房间有至少m个人。n<=1000,m,ai,bi<=10000;
题解:神仙dp。
考虑这个操作是可逆的。考虑最后一定是让所有人尽量往左匀,但是最后1房间只有少于m个人。那么反过来就是枚举每个房间有多少人并尽量向右匀,但是要保证任意时刻右面的房间不能匀到左边来。那么设dp[i,j]表示第i个房间能从左边匀出j个人待在i房间时,答案是多少。
那么若 j &lt; a i j&lt;a_i ,那么i+1房间要么有少于bi个人: d p ( i , j ) + k d p ( i + 1 , k ) , k &lt; b i dp(i,j)+k\rightarrow dp(i+1,k),k&lt;b_i ,要么i+1房间恰好有bi个人,这时可以把这j个人匀到右边去: d p ( i , j ) + j d p ( i + 1 , j + b i ) dp(i,j)+j\rightarrow dp(i+1,j+b_i)
否则若 a i j &lt; a i + b i a_i\le j&lt;a_i+b_i ,那么可以将i房间的j-ai个人匀到i+1房间(并且i+1房间不能有人,否则可以从右边匀到左边): d p ( i , j ) d p ( i + 1 , j a i ) dp(i,j)\rightarrow dp(i+1,j-a_i)
否则 a i + b i j a_i+b_i\le j ,那么所有人都可以到右边: d p ( i , j ) ( i + 1 , j ) dp(i,j)\rightarrow(i+1,j)
可以发现 j max ( m , max ( a i + b i ) ) j\le \max\left(m,\max(a_i+b_i)\right)

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int inf=-1e7,N=1003,M=20004;int a[N],b[N],f[2][M];
inline void upd(int &x,int y) { x=max(x,y); }
int main()
{
    int n=inn(),m=inn(),k=m;
    rep(i,1,n-1) a[i]=inn(),b[i]=inn(),upd(k,a[i]+b[i]);
    rep(i,0,m-1) f[1][i]=i;rep(i,m,k) f[1][i]=inf;
    rep(i,1,n)
    {
        int pf=inf,*now=f[i&1],*nxt=f[(i+1)&1];
        rep(j,0,k) nxt[j]=inf;
        rep(j,0,k) if(now[j]>inf)
        {
            if(j<a[i]) upd(nxt[j+b[i]],now[j]+b[i]),upd(pf,now[j]);
            else if(j<a[i]+b[i]) upd(nxt[j-a[i]],now[j]);
            else upd(nxt[j],now[j]);
        }
        rep(j,0,b[i]-1) upd(nxt[j],pf+j);
    }
    int ans=inf,*now=f[n&1];rep(i,0,k) upd(ans,now[i]);
    return !printf("%d\n",ans);
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/88664130
DP
DP?