题解P3745期末考试

我太菜了,QAQ

Luogu


简要分析

和洛谷的一篇分治的题解是一样的想法(是我看的她的),我只是一个更详细的代码解释,所以大家还是看洛谷题解吧

简要说一下。贪心的选取。在C花费多的情况下,若A比B花费多,就一直用B,否则就用A。同理,若C花费少,就用C。

其次是贪心的判断。选取时间点,看一看把所有的成绩都提升至该时间点的是否可以。


所有的见代码吧

#include
#include
using namespace std;
const int maxn=1e5+10;
unsigned long long t[maxn],d[maxn],used[maxn];
unsigned long long c[maxn],up[maxn],n,m,A,B,C;
//t[i]->时间上线为i的数目
unsigned long long flag,yes,last,x,ans;
inline void prework(){
    long long val=0,tot=0;
    if(flag!=3)//如果不是C大到离谱
        for(register int i=1;i<=last;i++)
            val+=tot*C,tot+=t[i],c[i]=val;
    //统计C的结果看一看到i这个时间点不满值是多少
    val=0;tot=0;
    for(register int i=1;i<=last;i++)
        val+=tot,tot+=d[i],used[i]=val;
    //看如果把时间线强行提到d[i],最多可以进行几次A
    val=0;tot=0;
    for(register int i=last;i>=1;i--)
        val+=tot,tot+=d[i],up[i]=val;
    //看如果把时间线强行提到d[i],最多要进行几次提升
}
inline void work(){
    //不用B的点
    long long now;ans=c[last];
    //如果一次提升也不进行,ans一直都是c[last]
    for(register int i=last;i>=1;i--){
        now=c[i];//枚举最后一天
        if(used[i]>=up[i]) now+=up[i]*A;
        //如果这个点要提升的次数大于最多可以用A提升的次数
        //那你就无能为力了,所以此时直接退出
        else break;
        ans>now?ans=now:ans=ans;
    }
}
inline void work1(){    
    ans=0ll;long long QAQ=0;
    //只用A,B的点,不能让学生等,
    //所以找到第一个有不满意值的时候,把所有的都提升到这个时候之前就好
    for(register int i=1;i<=last;i++)
        if(t[i]){QAQ=i;break;}//首先找到一个需要提升的点
        //即这个点有不满意值
    if(yes)//如果B>A 就先用A
        if(used[QAQ]>=up[QAQ]) ans+=up[QAQ]*A;
        //如果A还可以再用一会儿
        else ans+=used[QAQ]*A+(up[QAQ]-used[QAQ])*B;
        //当A用完了的时候,就只用B
    else ans+=up[QAQ]*B;
    //如果干脆A就B大,就只用B
}
inline void work2(){
    //毫无特色的点
    long long now;ans=c[last];
    for(register int i=last;i>=1;i--){
        now=c[i];
        if(yes)
            if(used[i]>=up[i]) now+=up[i]*A;
            else now+=used[i]*A+(up[i]-used[i])*B;
        else now+=up[i]*B;
        ans>now?ans=now:ans=ans;
    }
    //毫无特色的注释
}
int main(){
    scanf("%llu%llu%llu%llu%llu",&A,&B,&C,&n,&m);
    for(register int i=1;i<=n;i++) scanf("%llu",&x),t[x]++;
    for(register int i=1;i<=m;i++) 
        scanf("%llu",&x),last=max(x,last),d[x]++;
    if(B>A) yes=1;
    if(A==1e9&&B==1e9) flag=1;
    else if(A!=1e9&&B==1e9) flag=2;
    else if(C==1e16) flag=3;
    prework();
    if(flag==1) printf("%llu",c[last]);
    else if(flag==2) work();
    else if(flag==3) work1();
    else work2();printf("%llu",ans);
    //毫无特色的主函数(除了压行)
}

你可能感兴趣的:(题解P3745期末考试)