题目链接:https://atcoder.jp/contests/abc144/tasks/abc144_e

一道很简单的二分加贪心,但我在比赛时没过。因为我输入错了,它竟然加上样例还有6个点是对的,于是我查了半小时都没发现这件事,到最后只能怀疑是自己想法错了放弃。

首先二分答案sum。

现在的问题是你要将A,F数组一一对应,如果A[i]*F[i]>SUM,K-=A[i]-SUM/F[i],看K最后是否小于0。

然后你就会发现其实只要把A 从小到大,F从大到小排序,然后算出来的就是最优解

为什么呢?我们可以取两个数来试试。

取A1,A2,A1<A2。

取B1=SUM/F1,B2=SUM/F2,F1>F2。

减去的数很显然越小越好,所以减去的数为MIN(max(0,A1-B1)+max(0,A2-B2),max(0,A1-B2)+max(0,A2-B1))

总共有六种情况,分别为

1.A1<A2<B1<B2 MIN=0

2.A1<B1<A2<B2 MIN=0

3.B1<A1<A2<B2 MIN=min(A1-B1,A2-B1)=A1-B1

4.A1<B1<B2<A2 MIN=min(A2-B2,A2-B1)=A2-B2

5.B1<A1<B2<A2 MIN=min(A1-B1+A2-B2,A2-B1)=A1-B1+A2-B2

6.B1<B2<A1<A2 MIN=A1-B1+A2-B2

发现没有啊,都对应的啊

所以就直接贪心就好啦。程序如下。

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cstdio>
#include<vector>
using namespace std;
typedef long long ll;
int n,he;
ll a[1000009],b[1000009];
ll ans=0;
bool check(ll sum,ll k)
{
  he=1;
  for (int i=n;i>=1;i--)
  {
    if (a[he]*b[i]<=sum) {he++;continue;}
    if ((a[he]-sum/b[i])>k) return false;
    k-=a[he]-sum/b[i];
    he++;
  }
  return true;
}
int main()
{
  ll k;
  scanf("%d%lld",&n,&k);
  for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
  for (int i=1;i<=n;i++) scanf("%lld",&b[i]);
  sort(a+1,a+1+n); sort(b+1,b+1+n);
  ll l=0,r=0;
  r=b[n]*a[n];ans=r;
  while (l<=r)
  {
      ll mid=(l+r)/(ll)2;
      if (check(mid,k)) ans=mid,r=mid-1;
      else l=mid+1;
  }
  printf("%lld\n",ans);
  return 0;
}

 

posted on 2019-10-28 13:36  nhc2014  阅读(355)  评论(0编辑  收藏  举报