The 37th ACM/ICPC Asia Regional HangZhou Site Online Contest - F

9 篇文章 0 订阅

     本题通过率相当低....原因是绝大多数队都是直接贪心吧...找出A最小且B不为0的怪作为入口..可以将所有的B不为0的怪连起来...而中间的间隔可以把 B为0的怪干掉....最后再一一消灭 B 为0的怪...但这种思路是不全面的...如下列数据:

     6  20

     10  2

     10  2

   100  0

   100  0

   100  0

   100  0

    答案应该是  6  20   先打一个10  2...用2消灭两个100   0...再打一个10  2...用2消灭两个100 0...  但是如果按照裸的贪心..结果会是5  10...从10  2进入..两个10 2 连起来..有3个可用空隙...所以做出来的结果成了5  10

     那这个问题如何解决呢? 分为两方面看...若所有B不为0的怪连起来..间隔可以把B为0的都干掉..那么就是最有解了...否则的话就要做一个比较...是按原方案贪心更优..还是说将当前入口点独立出来..其B全都消灭B为0的怪物而不与后面的B不为0的怪相连.再A稍大的做入口再做更优.. .


PS:  比赛的数据太水了..感谢IsaacPei99和luyuncheng提供的数据..掐掉了我比赛时AC的代码..是有问题没考虑全面...代码已更新...


Program:

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<map>
#include<queue>
#include<stack>
#define ll long long
#define oo 2000000000
#define pi acos(-1)  
using namespace std; 
struct node
{
    ll A,B;
}p1[100055];
ll n,n1,p0[100055],ss[100055];   
bool cmp(node a,node b)
{
     return a.A<b.A;
}
ll GetMaxNumOfDeleP0(ll m,ll n0)
{
     int l=0,r=n0+1,mid;
     while (r-l>1)
     {
            mid=(r+l)/2;
            if (ss[mid]>m) r=mid;
               else l=mid;
     }
     return l; 
}
node dfs(node h,ll x,ll m,ll n0)
{ 
     node q=h;
     if (m<p1[x].A || x>n1) return h;
     ll sum=0,i; 
     for (i=x;i<=n1;i++) sum+=p1[i].B-1;
     sum++;    
     h.A+=n1-x+1; 
     m-=p1[x].A;
     h.B+=p1[x].A;
     if (sum>=n0) 
     {
           h.A+=n0;
           n0=0; 
     }else
     {  
          //-----------------
           q.A+=1+p1[x].B;
           q.B+=p1[x].A; 
           q=dfs(q,x+1,m,n0-p1[x].B);
          //-----------------
           n0-=sum; 
           h.A+=sum;
           i=GetMaxNumOfDeleP0(m,n0);
           h.A+=i;  h.B+=ss[i];
           if (q.A>h.A || q.A==h.A && q.B<h.B)  h=q;
     } 
     return h;
}
int main()
{  
    ll T,t,i,j,A,B,m,n0;
    node ans,h; 
    scanf("%I64d",&T);
    for (t=1;t<=T;t++)
    {
           scanf("%I64d%I64d",&n,&m);
           n1=n0=0;  
           for (i=1;i<=n;i++)
           {
                  scanf("%I64d%I64d",&A,&B);
                  if (B) 
                  {
                         n1++; 
                         p1[n1].A=A;  p1[n1].B=B;  
                  }else  p0[++n0]=A;  
           }  
           sort(p1+1,p1+1+n1,cmp); 
           sort(p0+1,p0+1+n0);
           memset(ss,0,sizeof(ss));
           for (i=1;i<=n0;i++) ss[i]=p0[i]+ss[i-1];
           ans.A=ans.B=0;  
           ans=dfs(ans,1,m,n0);  
           i=GetMaxNumOfDeleP0(m,n0);   
           h.A=i; h.B=ss[i];
           if (h.A>ans.A || h.A==ans.A && h.B<ans.B)  ans=h;
           printf("Case %I64d: %I64d %I64d\n",t,ans.A,ans.B); 
    }    
    return 0;
}
/*
7
3 5
4 1
5 1
7 7
2 1
2 2
4 0 
5 5
10 1
4 1
5 2
110 0
1 0
3 5
1 0 
2 0
3 0
6 20
10 2
10 2
100 0
100 0
100 0
100 0
5 7 
7 1
7 1
1 0
1 0
1 0
4 5
4 1
1 0
2 0
1 0
*/



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值