蒟蒻第一次公开比赛A题好激动啊。。。。。。
【问题描述】
天天暑假时帮别人寄送快递,经历了一个暑假,天天积累了不少数据,想对快递公司进行下评分,得到快递公司的质量水平。
总共有 n 家快递公司,编号为 1..n。现在天天有 m 天的寄送快递数据,其中第 i 天使用第 ei 家快递公司,快递在路上花了 ti 天时间。开始每个快递公司的评分都为 0,对于第i家快递公司,如果第i个包裹花了 ti 天寄到,
那么对这家快递公司的评分贡献为 2 − ti,(如果花的时间超过两天得分就会变成负的啦)。
然而事情没有这么简单,如果某天的数据丢掉了,天天为了公平起见就忽略掉这天的数据。于是快递公司联盟决定雇佣s个小偷,小偷可以偷最多 s 天的数据,使得每个公司的信用得分至少增加 k,且所有快递公司的信用总和尽量大。
若如果被偷以后,无法让每个公司的信用得分都至少增加 k,输出−23333333,否则请你输出被偷后, 所有快递公司的信用得分的和最多增加多少。
【输入格式】
第一行四个整数 n, m, s, k,其中 1 ≤ n, m ≤ 100, 000, 0 ≤ s ≤ m, 0 ≤k ≤ 1e9。
接下来 m 行,每行两个整数。接下来的第 i 行为 ei, ti,其中 1 ≤ ei ≤n, 0 ≤ ti ≤ 1e9。
【输出格式】
一个整数,为题目要求的答案。
2
【样例输入】
2 5 4 22
1 1
1 40
2 25
2 30
2 0
【样例输出】
89
【样例解释】
小偷可以偷 4 天的数据,但是小偷实际上只偷了第 2, 3, 4 天的数据,1
号公司获得了 38 分的提升,2 号公司获得了 23 + 28 分的提升,都满足了
最少提升 22 分的要求。
【数据规模和约定】
对于 30% 的数据,1 ≤ n, m ≤ 20。
对于 100% 的数据,1 ≤ n, m ≤ 200, 000
这个题就是个贪心,首先对于所有的数据,在读入时预先减去2,然后按照每个公司的数据,从大到小排序。
然后开始怼每一个公司,在这个公司的信用分到达k之前,只要是大于0的数据都要选。
接着检查是否每个公司的信用分都能到达k,如果有达不到的,就可以直接输出一个-23333333结束了。
然后将所有没被偷的数据从大到小排序,偷掉尽可能多的信用分大于0的数据,这就是最后的结果。
#include<cstdio> #include<algorithm> using namespace std; void read(int &y) { y=0;char x=getchar(); while(x<'0'||x>'9') x=getchar(); while(x>='0'&&x<='9') { y=y*10+x-'0'; x=getchar(); } } struct com { int t,e; }a[200005]; bool cmp(com x,com y) { return (x.e<y.e||(x.t>y.t&&x.e==y.e)); } bool b[200005],w[200005]; int n,m,s,k,p[200005]; long long ans; int main() { // freopen("express.in","r",stdin); // freopen("express.out","w",stdout); read(n);read(m);read(s);read(k); for(int i=1;i<=m;i++) { read(a[i].e); read(a[i].t); a[i].t-=2; } sort(a+1,a+m+1,cmp); for(int i=1;i<=m;i++) { if(s<=0) break; if(b[a[i].e]==0&&a[i].t>0) { w[i]=1;s--; p[a[i].e]+=a[i].t; if(p[a[i].e]>=k) b[a[i].e]=1; } } for(int i=1;i<=n;i++) { if(b[i]==0) { printf("-23333333"); return 0; } ans+=p[i]; } if(s>0) { int l=0; for(int i=1;i<=m;i++) { if(w[i]==0) p[++l]=a[i].t; } sort(p+1,p+l+1); for(int i=l;i>0;i--) { if(p[i]>0&&s>0) { ans+=p[i]; s--; } } } printf("%lld",ans); return 0; }