1 条题解

  • 0
    @ 2026-5-9 1:09:11

    非常有趣的一道题,乍一看很鬼,实际上仔细思考一下就能得到答案。
    闲话少说,切入正题——


    首先,我们来想想这个小矮人排列的大致次序。
    如果把高的给弄出去,那么这个贡献没了,很有可能导致只有这个高的一个人出去剩下的矮子全出不去的情况。
    那么矮的弄出去呢?显然,矮的弄出去对人梯的高度损失是最小的,也可以让更多的矮子出去。
    综上所述,我们就按照 ai+bia_i+b_i 从小到大排列矮人。


    然后问题来了,我们应该如何统计答案呢?
    可以用 dp 鸭~
    fif_i 为当前出去了 ii 个人能堆起来最高的高度(不算手)。
    要不然,pp 号小矮人不出去,fif_i 还是 fif_i
    要不然,pp 号小矮人滚出去,fif_i 就变成了 fi1apf_{i-1}-a_p
    所以状态转移方程就出来了:fi=max(fi,fi1ap) f_i=\max(f_i,f_{i-1}-a_p)


    上代码!

    #include<iostream>
    #include<algorithm> 
    #include<cstring>
    using namespace std;
    struct node{
    	int a,b;
    }A[2021];
    bool cmp(node &x,node &y)//排序比较器
    {
    	return x.a+x.b<y.a+y.b;
    }
    int f[2021];
    int main()
    {
    	memset(f,128,sizeof(f));//这里的 128 运用到了补码原理,总之你只要知道是最小值就好了。
    	int n,h;
    	cin>>n;
    	for(int p=1;p<=n;p++)
    		cin>>A[p].a>>A[p].b;
    	cin>>h;
    	sort(A+1,A+n+1,cmp);//排序
    	f[0]=0;//没人出去
    	for(int p=1;p<=n;p++)//初始化没人出去的情况,显然这个时候要累加 a[p]
    		f[0]+=A[p].a;
    	for(int p=1;p<=n;p++)//根据上面的方程 dp
    		for(int i=p;i>=1;i--)
    			if(f[i-1]+A[p].b>=h)//如果算上这个人的手能出去
    				f[i]=max(f[i],f[i-1]-A[p].a);
    	for(int p=n;p>=0;p--)
    		if(f[p]>=0)
    		{
    			cout<<p<<endl;
    			return 0;
    		}
    }
    
    • 1

    信息

    ID
    4839
    时间
    1000ms
    内存
    128MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者