BZOJ 4141 [Thu Summer Camp 2013]魔塔

权限题qwq

以下设值域大小为\(m\)

先考虑枚举攻击力,因为首先攻击力决定每个怪物的攻击次数,然后对于每个怪物,攻击次数为\(\lceil\frac{hp_i}{ATK-def_i}\rceil\),本质不同的攻击次数只有\(2\sqrt m\),所以这一方面枚举复杂度只要\(n\sqrt m\).

然后考虑防御力和血量,血量是由防御力决定的,为\(\sum_i \lceil\frac{hp_i}{ATK-def_i}\rceil max(atk_i-DEF,0)\)(输出时要+1,因为打完后血量要非负),等价于\(\sum_i \lceil\frac{hp_i}{ATK-def_i}\rceil atk_i-\sum_i \lceil\frac{hp_i}{ATK-def_i}\rceil min(atk_i,DE)\),那么从小到大枚举防御力,后面那一坨\(\sum_i \lceil\frac{hp_i}{ATK-def_i}\rceil min(atk_i,DE)\)就可以看成一堆分段函数的和,并且是个斜率不增的上凸壳的形式,前面那一坨减去某个防御力\(x\)\(y\)值就是对应防御力的血量.然后防御力每\(+1\),需要的血量也会减少,

这时\(x\)的最优取值为某一个点,并且后面那一小段的斜率\(\le cost\_def\),因为前面部分防御力增加带来的代价小于因为血量减少带来的收益.所以可以每次二分,然后更新答案.不过随着攻击力的增长,这个\(x\)的值是单调不增的,所以可以每次直接从上一个\(x\)往后移

感觉跑的比较慢qwq

#include<bits/stdc++.h>
#define LL long long
#define db double

using namespace std;
const int N=5000+10,M=1e6+10;
int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
vector<int> ls[M<<1];
vector<int>::iterator it;
int ca,cd;
int n,bear[N][3],mxat,z,mxde,mxhp,a2,a3;
LL dt[N],c1[M],c2[M],sm,mx=1ll<<50,a1;
void ad(int x,LL y)
{
	LL yy=x*y;
	while(x<=z) c1[x]+=y,c2[x]+=yy,x+=x&(-x);
}
LL gsm1(int x){LL an=0;while(x) an+=c1[x],x-=x&(-x);return an;}
LL gsm2(int x)
{
	LL an=0,fx=x+1;
	while(x) an+=fx*c1[x]-c2[x],x-=x&(-x);
	return an;
}

int main()
{
    n=rd(),ca=rd(),cd=rd();
    for(int i=1;i<=n;++i)
    {
		bear[i][0]=rd(),bear[i][1]=rd(),bear[i][2]=rd();
		mxhp=max(mxhp,bear[i][0]);
		mxat=max(mxat,bear[i][1]);
		mxde=max(mxde,bear[i][2]);
    }
    for(int i=1;i<=n;++i) dt[i]=0,ls[mxde+1].push_back(i);
    int cn=n;
	z=mxat;
    for(int i=mxde+1;cn&&i<=mxde+mxhp;++i)
    {
		if(!ls[i].size()) continue;
		for(it=ls[i].begin();it!=ls[i].end();++it)
		{
			int x=*it;
			sm-=dt[x]*bear[x][1],ad(1,-dt[x]),ad(bear[x][1]+1,dt[x]);
			dt[x]=(bear[x][0]+i-bear[x][2]-1)/(i-bear[x][2]);
			sm+=dt[x]*bear[x][1],ad(1,dt[x]),ad(bear[x][1]+1,-dt[x]);
			if(dt[x]==1){--cn;continue;}
			ls[(bear[x][0]+dt[x]-1-1)/(dt[x]-1)+bear[x][2]].push_back(x);
		}
		ls[i].clear();
		while(z>1&&gsm1(z)<=cd) --z;
		LL hp=sm-gsm2(z),nw=1ll*i*ca+1ll*z*cd+hp;
		if(mx>nw) mx=nw,a1=hp+1,a2=i,a3=z;
    }
	printf("%lld %d %d\n",a1,a2,a3);
    return 0;
}
posted @ 2019-06-30 19:58  ✡smy✡  阅读(198)  评论(1编辑  收藏  举报