1 条题解

  • 0
    @ 2025-8-24 21:48:07

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar cyy233
    哲学点亮人生智慧

    搬运于2025-08-24 21:48:07,当前版本为作者最后更新于2019-07-22 15:32:17,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    废话不说,直接开讲。


    这道题和访问美术馆及其相似,就是加了01背包。。。 是一道不错的树形dp

    我们可以采用线段树的存储思想 虽然我还不会线段树

    我们把当前节点作为x,左节点就是2x,右节点即2x+1

    这样的话,程序看上去,简单,直观多了

    唯一的缺点就是耗空间,像我Re到飞起

    对于dp,可以直接在读入中做。

    还有这道题有两个坑点,一是小偷在s-1秒时就必须离

    二是走廊必须走一来一回两遍

    所以做dfs前s--,做背包时前t*2

    背包容量下限加一个时间t(*2)

    然后就和选课一样,最多时间s(-1),最少t(*2)

    从左节点下限一秒也不花,上限走这条走廊的时间i-t(*2),我们有公式

    dp[x][i]=max(dp[x][i],dp[x<<1][j]+dp[x<<1|1][i-j-t]);

    x为当前节点,i为走该走廊的时间

    左儿子花j秒,右儿子花i-j-t(*2)秒,走走廊t(2)秒(t是读入时的t,可以在dp前就t2

    下面给出代码

    #include<bits/stdc++.h>
    using namespace std;
    int s,dp[10010][10010],ans,a[2010],b[2010];
    void read(int x){
    
    	int t,k;
    	cin>>t>>k;
    	t=t<<1;
    	if(k>0){
    		for(int i=1;i<=k;i++){
    			cin>>a[i]>>b[i];
    		}	
    		for(int i=1;i<=k;i++){
    			for(int j=s;j>=t+b[i];j--){
    				dp[x][j]=max(dp[x][j-b[i]]+a[i],dp[x][j]);
    			}
    		}
    	}
    	if(!k){
    		read(x<<1);
    		read(x<<1|1);
    		for(int i=s;i>=t;i--)
    			for(int j=0;j<=i-t;j++){
    				dp[x][i]=max(dp[x][i],dp[x<<1][j]+dp[x<<1|1][i-j-t]);
    			}
    	}
    }
    int main()
    {
    	ios::sync_with_stdio(false);
    	//freopen("steal.in","r",stdin);
    	//freopen("steal.out","w",stdout);
    	cin>>s;
    	s--;
    	read(1);
    	cout<<dp[1][s];
    	return 0;
    }
    
    

    不看美术馆的题解还想不到这样保存

    • 1

    信息

    ID
    2442
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者