这三道题分别对应bzoj4868~4870,pdf没法往这放,因此放弃了。

T1:

方法1(正解):三分法

考虑暴力枚举最晚公布的时间x,关注到2操作是没有负面影响的1操作,所以如果A大于B,那么只需用2操作就可以了,否则先用1操作,不能用1操作后再用2操作。这样就能把b数组全部变成小于等于x,在加上额外的不愉快度就可以了。这个算法的时间复杂度是,可以拿60分。 
如果你去打表就能发现不愉快度关于时间是一个下凸函数,可以用三分做。具体的证明是这样的: 
1、修改代价关于时间是单调递减的,也就是说越晚出成绩修改代价越小; 
2、额外代价关于时间是单调递增的,也就是说越晚出成绩额外代价越大; 
3、最重要的一句,这两个函数的导数都是递增的。
感性的想一下,拿额外代价举例子,比如五个人的时间分别是1、2、2、3、3,时间从1改到2,需要额外代价的1个人(第一个人),但是从2改到3,需要额外代价的就变成了3个人,从3改到4所有的人都需要额外代价,也就是说刚开始额外代价增加慢,到后来额外代价增加快。 
4、这样把这两个函数加起来,导数也是递增的,所以它是一个下凸函数(当然也有可能退化成单调函数)。

#include<cstdio>
#include<iostream>
#include<algorithm>
#define MN 100000
#define ll long long
using namespace std;
inline int read()
{
    ll x = 0; char ch = getchar();
    while(ch < '0' || ch > '9') ch = getchar();
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x;
}

int n,m,t[MN+5],s[MN+5];
ll A,B,C,ans=1e18;

ll calc(int tms)
{
    ll sum=0,left=0,need=0;
    for(int i=1;i<=n;++i) sum+=C*max(0,tms-t[i]);
    for(int i=1;i<=m;++i)
        if(s[i]>tms) need+=s[i]-tms;
        else left+=tms-s[i];
    if(B<A)return sum+need*B;
    else if(left>=need) return sum+need*A;
    else return sum+left*A+(need-left)*B;
}

void Solve(int l,int r)
{
    if(r-l<=1)
    {
        for(int i=l;i<=r;++i) ans=min(ans,calc(i));
        return;
    }
    int m1=(r-l+1)/3+l,m2=(r-l+1)/3*2+l;
    if(calc(m1)<calc(m2)) Solve(l,m2-1);
    else Solve(m1+1,r);
}

int main()
{
    A=read();B=read();C=read();
    n=read();m=read();int mx=0;
    for(int i=1;i<=n;++i) mx=max(mx,(t[i]=read()));
    for(int i=1;i<=m;++i) mx=max(mx,(s[i]=read()));
    Solve(1,mx);
    printf("%lld\n",ans);
    return 0;
}
T1-1

相关文章:

  • 2022-02-24
  • 2021-09-04
  • 2021-09-02
  • 2021-07-10
  • 2021-07-31
  • 2021-09-01
  • 2021-06-10
  • 2021-12-01
猜你喜欢
  • 2022-12-23
  • 2021-08-19
  • 2022-02-21
  • 2021-11-22
  • 2021-10-27
  • 2021-09-15
相关资源
相似解决方案