zoukankan      html  css  js  c++  java
  • BZOJ 4141 [Thu Summer Camp 2013]魔塔

    权限题qwq

    以下设值域大小为(m)

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

    然后考虑防御力和血量,血量是由防御力决定的,为(sum_i lceilfrac{hp_i}{ATK-def_i} ceil max(atk_i-DEF,0))(输出时要+1,因为打完后血量要非负),等价于(sum_i lceilfrac{hp_i}{ATK-def_i} ceil atk_i-sum_i lceilfrac{hp_i}{ATK-def_i} ceil min(atk_i,DE)),那么从小到大枚举防御力,后面那一坨(sum_i lceilfrac{hp_i}{ATK-def_i} ceil 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
    ",a1,a2,a3);
        return 0;
    }
    
  • 相关阅读:
    数据库知识整理<二>
    数据库知识整理<一>
    面试经历感悟:
    JDK,J2EE,J2SE,J2ME的概念区别是什么呢?
    HTML与JSP页面的区别
    Java并发编程:深入剖析ThreadLocal
    剖析错误原理并解决Hibernate出现No TransactionManagerLookup specified!错误
    MyEclipse中jar包管理技巧
    String,StringBuffer与StringBuilder的区别??
    POJO / JavaBean / Entity Bean
  • 原文地址:https://www.cnblogs.com/smyjr/p/11110980.html
Copyright © 2011-2022 走看看