• 【CCPC-Wannafly Winter Camp Day4 (Div1) I】咆咆咆哮(三分+贪心)


    点此看题面

    大致题意:(n)张卡牌,每张卡牌有两种用法:使场上增加一个伤害为(a_i)的生物,或使场上所有生物伤害增加(b_i)。求最大总伤害。

    三分

    我们可以三分使用(a_i)的卡牌张数

    证明如下:

    假设使用(a_i)的卡牌张数最优为(x),此时选用的(b_i)总和为(t)

    • 证明:从最优决策点向左总伤害值递减

      此时如果将一张选(a_i)的卡牌改为选(b_i),则伤害变化值应为(b_i*(x-1)-a_i-t)

      因为原先状态为最优状态,所以该操作肯定不能使答案更优,也就是说:(b_i*(x-1)-a_i-tle0)

      再考虑若当前使用(a_i)的卡牌张数是(y(y<x)),选用的(b_i)总和为(t'),则伤害变化值应为(b_i*(y-1)-a_i-t')

      由于(y<x)(b_i>0),所以(b_i*(y-1)<b_i*(x-1))

      由于使用(a_i)的卡牌张数减少,所以使用(b_i)的卡牌张数增加,因此(t'>t)

      (a_i)是不变的,且(b_i*(x-1)-a_i-tle0),所以(b_i*(y-1)-a_i-t')必然小于(0)

      也就是说伤害变化值为负数,肯定是不优的。

      可见从最优决策点向左总伤害值递减

    • 证明:从最优决策点向右总伤害值递减

      此时如果将一张选(b_i)的卡牌改为选(a_i),则伤害变化值应为(a_i+t-b_i*(x-1))

      因为原先状态为最优状态,所以该操作肯定不能使答案更优,也就是说:(a_i+t-b_i*(x-1)le0)

      再考虑若当前使用(a_i)的卡牌张数是(y(y>x)),选用的(b_i)总和为(t'),则伤害变化值应为(a_i+t'-b_i*(y-1))

      由于(y>x)(b_i>0),所以(b_i*(y-1)>b_i*(x-1))

      由于使用(a_i)的卡牌张数增加,所以使用(b_i)的卡牌张数减少,因此(t'<t)

      (a_i)是不变的,且(a_i+t-b_i*(x-1)le0),所以(a_i+t'-b_i*(y-1))必然小于(0)

      也就是说伤害变化值为负数,肯定是不优的。

      可见从最优决策点向右总伤害值递减

    综上所述,这是一个单峰函数,具备可三分性。

    贪心求出最大伤害

    上面我们已经证明了这道题有可三分性,那对于确定的使用(a_i)的卡牌张数,我们该如何求出最大伤害呢?

    这可以用贪心

    假设确定使用(a_i)(x)张,则我们先定义一个(res)统计答案,初始化它为(sum_{i=1}^na_i)

    由于使用(a_i)的卡牌张数是确定的,则对于第(i)张牌,它使用(b_i)能造成的伤害为(b_i*x)

    然后,我们用它使用(b_i)能造成的伤害,减去它使用(a_i)能造成的伤害,就得到了(b_i*x-a_i)

    显然,我们可以将这进行排序,然后选择最大的(n-x)个与(res)相加,这样就能清除原先选择(a_i)(res)造成的贡献,并加上选择(b_i)(res)造成的贡献。

    具体实现详见代码。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define LL long long
    #define Gmax(x,y) (x<(y)&&(x=(y)))
    using namespace std;
    int n,a[N+5],b[N+5];LL s[N+5];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define tn (x<<3)+(x<<1)
    		#define D isdigit(c=tc())
    		char c,*A,*B,FI[FS];
    	public:
    		I FastIO() {A=B=FI;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
    		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    }F;
    I LL GetAns(CI x)//求出在使用a[i]的卡牌张数为x时的最优答案
    {
    	RI i;Reg LL res=0;for(i=1;i<=n;++i) res+=a[i],s[i]=1LL*b[i]*x-a[i];//初始化答案
    	for(sort(s+1,s+n+1),i=n;i^x;--i) res+=s[i];return res;//排序+贪心,返回答案
    }
    I LL Solve(RI l,RI r)//三分
    {
    	RI i,mid1,mid2;Reg LL res=0,t;
    	W(r-l>2) mid1=l+(r-l)/3,mid2=r-(r-l)/3,GetAns(mid1)>GetAns(mid2)?r=mid2:l=mid1;//三分
    	for(i=l;i<=r;++i) t=GetAns(i),Gmax(res,t);return res;//求答案
    }
    int main()
    {
    	RI i;for(F.read(n),i=1;i<=n;++i) F.read(a[i],b[i]);//读入数据
    	return printf("%lld",Solve(1,n)),0;//输出答案
    }
    
  • 相关阅读:
    C# 利用Log4Net进行日志记录
    驰骋工作流引擎JFlow与activiti的对比之2种结构化模式
    驰骋工作流引擎JFlow与activiti的对比之4种高级分支同步模式
    工作流引擎JFlow与activiti 对比分析(一)5种基本控制流模式的对比
    "整数"组件:<int> —— 快应用组件库H-UI
    "短整数"组件:<short> —— 快应用组件库H-UI
    "字节型整数"组件:<byte> —— 快应用组件库H-UI
    "图片验证码"组件:<vcode> —— 快应用组件库H-UI
    "手机验证码"组件:<smscode> —— 快应用组件库H-UI
    "邮政编码"组件:<postcode> —— 快应用组件库H-UI
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CometOJDay4Div1I.html
Copyright © 2020-2023  润新知