[Shoi2017]期末考试

传送门

题目抽象一下:

分为两类:关于科目的不愉快度(A,B)和关于学生的不愉快度(C)

重点是想到二分 所有科目的结束时间。

对于超过结束时间的科目,如果B<=A,那么就尽量用B去更改时间,否则用A更改时间,不能再使用A了就再用B去更改。

而对于学生,小于时间界限i的还要产生C的不愉快度。

这样做所有情况都可以覆盖到。

然鹅这道题很容易爆LL啊。

#include<bits/stdc++.h>
#define LL long long
#define N 100003
#define INF 10000000000000000
using namespace std;
LL read()
{
    LL x=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x*f;
}
LL maxx=-1,minn=INF;
int t[N],b[N];
int n,m;
LL A,B,C;
LL stu[N],ke[N];
LL k1=0,k2=0,s=0;//满足时间的科目,不满足时间的科目,满足时间的学生 个数
LL sum1=0,sum2=0,sum3=0;//满足时间的科目,不满足时间的科目,满足时间的学生 个数*时间 
LL ans=INF;
void work1()
{
    LL res=0;
    for(int i=1;i<=n;++i)
      if((LL)t[i]<maxx)res+=(LL)(maxx-t[i])*(LL)C;
    printf("%lld\n",res);
}
void work2()
{
    for(int i=100000;i>=1;--i)
    {
        LL res=0;
        sum1-=ke[i]*i;k1-=ke[i];
        sum2+=ke[i]*i;k2+=ke[i];
        sum3-=stu[i]*i;s-=stu[i];
        if(i>minn)continue;
        if(!sum2)continue;
        if(A<B)
        {
            LL p=k1*i-sum1;//前面满足的 
            LL q=sum2-k2*i;//后面不满足的
            res+=min(p,q)*A; 
            q-=min(p,q);
            if(q)res+=q*B;
        }
        else 
        {
            LL q=sum2-k2*i;//后面不满足的
            res+=q*B;
        }
        ans=min(ans,res);
    }
    printf("%lld\n",ans);
}
int main()
{
    freopen("exam.in","r",stdin);
    freopen("exam.out","w",stdout);
    A=read(),B=read(),C=read();
    n=read(),m=read();
    for(int i=1;i<=n;++i)t[i]=read(),stu[t[i]]++,s++,sum3+=t[i],minn=min(minn,(LL)t[i]);
    for(int i=1;i<=m;++i)b[i]=read(),ke[b[i]]++,k1++,sum1+=b[i],maxx=max(maxx,(LL)b[i]);
    if(A==1000000000&&B==1000000000&&C<=100){work1();return 0;}
    if(C==10000000000000000){work2();return 0;}
    sort(t+1,t+1+n);sort(b+1,b+1+m);
    for(int i=100000;i>=1;--i)
    {
        LL res=0;
        sum1-=ke[i]*i;k1-=ke[i];
        sum2+=ke[i]*i;k2+=ke[i];
        sum3-=stu[i]*i;s-=stu[i];
        if(!sum2)continue;
        if(A<B)
        {
            LL p=k1*i-sum1;//前面满足的 
            LL q=sum2-k2*i;//后面不满足的
            res+=min(p,q)*A; 
            q-=min(p,q);
            if(q)res+=q*B;
        }
        else 
        {
            LL q=sum2-k2*i;//后面不满足的
            res+=q*B;
        }
        res+=(s*i-sum3)*C;
        ans=min(ans,res);
    }
    printf("%lld\n",ans);
} 
View Code

转载于:https://www.cnblogs.com/yyys-/p/11544228.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值