• bzoj3174 [Tjoi2013]拯救小矮人


    Description

    一群小矮人掉进了一个很深的陷阱里,由于太矮爬不上来,于是他们决定搭一个人梯。即:一个小矮人站在另一小矮人的 肩膀上,知道最顶端的小矮人伸直胳膊可以碰到陷阱口。对于每一个小矮人,我们知道他从脚到肩膀的高度Ai,并且他的胳膊长度为Bi。陷阱深度为H。如果我 们利用矮人1,矮人2,矮人3,。。。矮人k搭一个梯子,满足A1+A2+A3+....+Ak+Bk>=H,那么矮人k就可以离开陷阱逃跑了,一 旦一个矮人逃跑了,他就不能再搭人梯了。
    我们希望尽可能多的小矮人逃跑, 问最多可以使多少个小矮人逃跑。

    Input

    第一行一个整数N, 表示矮人的个数,接下来N行每一行两个整数Ai和Bi,最后一行是H。(Ai,Bi,H<=10^5)

    Output

    一个整数表示对多可以逃跑多少小矮人

    Sample Input

    样例1

    2
    20 10
    5 5
    30

    样例2
    2
    20 10
    5 5
    35

    Sample Output

    样例1
    2

    样例2
    1

    HINT

    数据范围

    30%的数据 N<=200

    100%的数据 N<=2000

     
    首先orz hzwer
    这题是贪心完dp
    就是正常做法:已知两个相邻的小矮人a和b,考虑交换ab位置的代价
    首先如果a在b下面,那么第一次的高度是a.a+b.a+b.b,第二次的高度是a.a+a.b
    然后如果b在a下面,那么第一次的高度是a.a+b.a+a.b,第二次的高度是b.a+b.b
    我们要考虑的就是交换ab会对原来的答案有什么影响
    比较直观的想法是关键看第二次的高度,因为第二次的高度更高的那个,最终一定比另一个优。
    还要考虑可能会出现的第二个比另一个更高但是第一个不如另一个的情况。
    即可能出现a.a+a.b>b.a+b.b,但是a.a+b.a+b.b<a.a+b.a+a.b,即a.b>a.a+b.b。要知道这是完全可能的
    考虑在这种情况下,假设a.b>a.a+b.b,那不交换的情况下第一次是a.a+b.a+b.b<a.b+b.a<b.b+a.b+a.a因此交换完还是更优
    所以只需a.a+a.b<a.a+b.b即可
    上面我们已经证明按贪心完的顺序取是最优的,但是还要确定最多能走掉多少个
    接下来要dp:令f[i]表示走完i个矮人之后还能取到的最大高度
    这样贪心的作用就出来了:按照贪心完的顺序取走矮人,可以保证最优。
    一开始初始化f[0]表示没有矮人走掉,f[0]=Σa[i]。
    然后就是枚举取到第i个矮人,可以用它来更新f[j]的情况是f[j]+ai.b>=m。
    这样就可以算出最大值了
    这题解真TM长……要把贪心讲清楚真不容易啊
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<deque>
    #include<set>
    #include<map>
    #include<ctime>
    #define LL long long
    #define inf 0x7ffffff
    #define pa pair<int,int>
    #define pi 3.1415926535897932384626433832795028841971
    using namespace std;
    inline LL read()
    {
        LL x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void write(LL a)
    {
    	if (a<0){printf("-");a=-a;}
    	if (a>=10)write(a/10);
    	putchar(a%10+'0');
    }
    struct man{int a,b;}a[100010];
    inline bool operator <(const man &a,const man &b)
    {return a.a+a.b<b.a+b.b;}
    int n,lim,ans;
    int f[100010];
    int main()
    {
    	memset(f,-1,sizeof(f));f[0]=0;
    	n=read();
    	for(int i=1;i<=n;i++)
    	{
    		a[i].a=read();a[i].b=read();
    		f[0]+=a[i].a;
    	}
    	lim=read();
    	sort(a+1,a+n+1);
    	for (int i=1;i<=n;i++)
    	{
    		for (int j=ans;j>=0;j--)
    		{
    			if (a[i].b+f[j]>=lim)f[j+1]=max(f[j+1],f[j]-a[i].a);
    			if (f[ans+1]>=0)ans++;
    		}
    	}
    	write(ans);
    	return 0;
    }
    

      

    ——by zhber,转载请注明来源
  • 相关阅读:
    将枚举的键值绑定到下拉列表框
    获取checkbox的选中值
    ADO.NET中的五个主要对象
    10.MVC框架开发(Ajax应用)
    9.MVC框架开发(关于ActionResult的处理)
    8.MVC框架开发(URL路由配置和URL路由传参空值处理)
    7.MVC框架开发(创建层级项目)
    6.MVC框架开发(文件上传)
    5.MVC框架开发(强类型开发,控制器向界面传递数据的几种方法)
    4.MVC框架开发(母版页的应用、按钮导致的Action处理、从界面向控制器传数据和HtmlHelper控件的实现(注册的实现))
  • 原文地址:https://www.cnblogs.com/zhber/p/4158654.html
Copyright © 2020-2023  润新知