您的位置:首页 > 其它

CodeForces 614D 二分+贪心

2017-09-10 23:26 405 查看
原题链接: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 long
using 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 30
1
62
31

3 5 10 1 5
1 3 1

2 6 0 1 4
5 1

5
5 5

3 5 10 1 339
1 3 1

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  codeforces