CodeForces 614D 二分+贪心

来源:互联网 发布:万网域名怎么转让 编辑:程序博客网 时间:2024/05/16 11:38

原题链接:http://codeforces.com/problemset/problem/614/D

题意:有n门学科,每一门最高水平为A,一共可以提高的水平为m,计算经过提升后的最大得分,得分=(达到A分数的科目个数)*cf+(最低分数)*cm

最开始真的一脸懵逼完全不会啊
仔细想了想,可以枚举达到A的数目,把原数组从小到大排个序倒着选择成为满分的科目,然后在剩下没达到满分的科目里选择最低分。复杂度应该可以接受,我最开始想也是暴力枚举最低分判断合法好了,后来发现尼玛这不就是二分嘛

然后就愉快【呵呵】地开始码了

在check的时候真的饶了很久,最后发现其实预处理一个前缀和就很好计算了。要注意时刻维护你剩下的可以提高的分数【要保证这个值不能为负数】,至于计算的话用lower_bound找到第一个大于等于这个最小值的位置,然后就很好计算了。

多简单是吧,然后介绍我漫长【脑残】的调试过程:
1.最开始的数组要排序嘛,又要计算前缀和吗,我当时为了少打一个for循环就边读入边处理了,呵呵,错在哪多明显【于是WA在了第一个点】

2.考虑的ans的最初答案【就是不做任何改变】,但是,我没有考虑一个满分都没有的情况,最开始我想直接加到for循环里,发现不行【因为会导致j的计算少1】就只能在前面又加了一个二分最低分【于是WA在了第三个点】
然后这一天我就去睡了。= =

3.以上改完以后WA在了第五个点,好,我查。此时是晚自习。
发现第一次二分的时候求pos的时候没有考虑越界情况,于是当n=1的时候就挂了

4.接下来卡在了第19个点。我选择了找一只标程对拍。发现自己的输出答案有问题(虽然这不是我WA这个点的原因)我改写a2的地方竟然写了low。。。之后还有一个问题没找到错在哪。。
这只是一个小插曲,改了之后依旧错了,我发现我错的不是输出分数,而是输出最大得分,我的答案小了?(感谢codeforces给看数据)
漫长的查答案,不断地调整二分上下界,没用。。。
回家。
打开我的vim,打开614D的cpp,突然灵光一闪——
lower_bound()求的是大于等于的第一个数,那么我在统计小于这个数的时候是需要减1的啊啊啊啊啊啊啊啊啊啊啊啊

5.好了我A了【终于quq】

好有成就感啊,再一次见识了什么叫信息学竞赛的细节。。。。。

不过我的速度比某位dalao慢了一倍,仔细查看发现是我们二分的东西不一样,我二分的是最低分,他二分地是科目范围,从数据范围来看,前者是log(10^9),后者是log(10^5)。。。

激动到写博客留恋,虽然不是一道非常难的题。

以下AC代码:

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<vector>#include<cmath>#define maxn 100010#define ll long longusing namespace std;typedef pair<ll,int> P;P a[maxn];int n,cf,cm;ll A,m;ll sum[maxn];struct node{    int id;ll x;    bool operator <(node s)const{        return id<s.id;    }}out[maxn];void file(){    freopen("a.in","r",stdin);    freopen("a.out","w",stdout);}bool cmp(P a,P b){    return a.first<b.first;}int main(){    //file();    scanf("%d%I64d%d%d%I64d",&n,&A,&cf,&cm,&m);    int cnt=0;ll minn=1e18+7;    for(int i=1;i<=n;i++){        scanf("%I64d",&a[i].first);        a[i].second=i;minn=min(minn,a[i].first);        if(a[i].first>=A)cnt++;    }    sort(a+1,a+n+1,cmp);     for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i].first;    ll tp=m;ll ans=cnt*cf+minn*cm;int a1=cnt;ll a2=minn;    ll low;    ll l=1,r=A;    while(l<=r){        ll mid=(l+r)>>1;        int pos=lower_bound(a+1,a+n+1,P(mid,0))-a-1;        pos=min(pos,n);        ll cost=pos*mid-sum[pos];//printf("%lld %d %lld\n",mid,pos,cost);        if(cost>m)r=mid-1;        else low=mid,l=mid+1;    }    ll tp2=low*cm;    if(tp2>ans){        ans=tp2;a1=0;a2=low;    }       low=0;tp=m;    for(int i=n,j=1;i>=1;i--,j++){        tp-=(A-a[i].first);//printf("%d %lld\n",i,tp);        if(tp<0)break;        ll l=1,r=A;low=0;        while(l<=r){            ll mid=(l+r)>>1;            int pos=lower_bound(a+1,a+n+1,P(mid,0))-a-1;            pos=min(pos,i-1);            ll cost=pos*mid-sum[pos];            //printf("(%lld %lld %d %d %d %lld %lld\n",mid,a[i].first,i,j,pos,cost,tp);            if(cost>tp)r=mid-1;            else l=mid+1;        }        low=l-1;        ll tp2=low*cm+j*cf;//printf("1.%lld\n",tp2);        if(tp2>ans){            //printf("%d %d %d %lld %lld\n",tp,i,j,low,tp2);            ans=tp2;a1=j;a2=low;        }    }    printf("%I64d\n",ans);    //printf("(%lld %lld\n",a1,a2);    for(int i=n;i>=n-a1+1;i--){        out[i].x=A;    }    for(int i=1;i<=n-a1;i++){    //  if(a[i].second==1)printf("*%lld\n",a[i].first);        out[i].x=max(a[i].first,a2);    }    for(int i=1;i<=n;i++)out[i].id=a[i].second;    sort(out+1,out+n+1);    for(int i=1;i<=n;i++){        if(i!=n)printf("%I64d ",out[i].x);        else printf("%I64d\n",out[i].x);    }    return 0;} /*1 100 1 2 3016231 3 5 10 1 51 3 12 6 0 1 45 155 53 5 10 1 3391 3 1*/