2017.9.17 noip模拟赛day2—天天寄快递

蒟蒻第一次公开比赛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;
}
原文地址:https://www.cnblogs.com/zeroform/p/7541527.html