Codeforces Round #610 (Div. 2) C. Petya and Exam(贪心)

题目链接:https://codeforces.com/contest/1282/problem/C

 

题目大意:

  有n道题,一共T的答题时间,简单题需要时间a,难题需要b,每道题都有ddl,如果实际答题时间到达ti,那么这道题就必须要做,否则只能拿零分,每题一分,问最多能拿几分

 

题目思路:

  日常被C题卡。。。哭了。我刚开始想简单了,就直接双指针,如果做了一个题,其他题ddl到了,就一排全部带走,否则尽量做简单题。反例太多了。。。。。后来又看了题解。。。菜!强行总结出这种题技巧,就是只要出现过了某个时间点就会变性质的题目,那么这个时间点的附近时间点可能就是题目的关键!
  不卖关子了,首先我们可以发现,对于每个ddl的前一秒,如果能在这个时间点完成必做任务,而且没有超时,那么这个时间点就不会产生关联到其他题目的关键时间点。这个时间点的好处在于,把动态的过程(如果时间超过了某一题ddl,这题变成必做会影响结束时间)变成了静态(不再有题目变成必做,所以就是不用怕会有新的必做题出现)。这道题的做法就是,搞出所有题目ddl-1再加上T也就是考试结束时间,这些作为关键点,排序去重。然后判断每个时间点能够得到的分数。怎么判断呢?首先先看这个时间段有多少必做简单题数量 c 1 c1 c1和必做难题数量 c 2 c2 c2,直接用while即可,只要ddl小于等于正在枚举的时间点 t t t,那就是必做题,那么剩余时间就是 t − a ∗ c 1 − b ∗ c 2 t-a*c1-b*c2 tac1bc2,如果剩余时间是负数,就说明这个时间点不够完成必做任务直接歇逼,如果还有剩,那么聪明的大家伙肯定想到了,可以用来不是必做的题,由于简单题需要的时间少,所以先做简单题, m i n ( r s t / a , p p 1 − c 1 ) min(rst/a,pp1-c1) min(rst/a,pp1c1) 表示还能做多少简单题,要么是时间不够了,要么是题不够了,难题也一样,然后就能得到这个时间点一共能做的题,取max这题就结束战斗了。

 

以下是代码:

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
const int MAXN = 2e5+5;
const int MOD = 10007;
int x[MAXN],y[MAXN],p[MAXN];
int h[MAXN],k[MAXN];
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int n,T,a,b;
        scanf("%d%d%d%d",&n,&T,&a,&b);
        rep(i,1,n){
            scanf("%d",&x[i]);
        }
        int pos=0;
        int pp1=0,pp2=0;
        rep(i,1,n){
            scanf("%d",&y[i]);
            if(x[i])k[++pp2]=y[i];
            else h[++pp1]=y[i];
            p[++pos]=y[i]-1;
        }
        p[++pos]=T;
        sort(p+1,p+pos+1);
        sort(k+1,k+pp2+1);
        sort(h+1,h+pp1+1);
        pos=unique(p+1,p+pos+1)-p-1;
        ll ans=0;
        int c1=0,c2=0;
        h[pp1+1]=1e9+7;
        k[pp2+1]=1e9+7;
        rep(i,1,pos){
            while(h[c1+1]<=p[i])c1++;
            while(k[c2+1]<=p[i])c2++;
            ll temp=c1+c2;
            ll rst=p[i]-(ll)c1*a-(ll)c2*b;
            if(rst<0)continue;
            int num=min(rst/a,(ll)pp1-c1);
            temp+=num;
            rst-=num*a;
            num=min(rst/b,(ll)pp2-c2);
            temp+=num;
            ans=max(ans,temp);
        }
        printf("%I64d\n",ans);
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值