zoukankan      html  css  js  c++  java
  • BZOJ4141 THUSC2013 魔塔 贪心

    没得传送门


    考虑当(Atk)增大时,(Def)一定越来越没用,因为回合数在变少。所以考虑从小到大枚举(Atk)然后双指针计算。

    (f_i(x))表示在(Atk = i)时,(Def)(x-1)(x)时可以减少的血量的数量,易知(f_i(x) leq f_i(x - 1) , f_i(x) leq f_{i-1}(x))。对于每一个怪,当(Atk)确定之后,它的攻击回合数就确定了。对于(Atk = i),一个怪物的攻击力为(atk),攻击回合数为(T)时,相当于在函数(f_i(x))([1,atk])区间做一个前缀加(T)的操作。当攻击回合数减小的时候也相当于前缀减然后前缀加。

    不妨把这个问题变得更形象一点:有若干条线段,左端点为(1),右端点不固定,每一条线段都有一个权值。从(Def = x - 1)(Def = x)能够减少的血量就是覆盖了(x)点的所有线段的权值和。

    一件显然的事情是因为(Def)在不断变小,所以之前被当前点覆盖的线段在之后也一定被覆盖。

    所以我们可以设(num_i)表示右端点为(i)的所有线段的权值之和,然后我们考虑:当当前的(Def)覆盖的线段的权值之和(leq cd)时将(Def - 1),然后把(num_{Def - 1})加入,就可以更新出新的权值了。对于删线段和加线段只需要看一下当前加入线段的右端点和(Def)的关系并进行更新就可以了。在维护攻击防御值的时候同时维护血量以保证复杂度。

    那么最后的问题就是如何快速加入和删除线段,暴力做是(O(NHp))的,但是注意到(lceil frac{Hp}{i} ceil = lfloor frac{Hp - 1}{i} floor + 1)只有(sqrt{Hp})种取值,我们可以预处理出每一个转移点,就可以做到(O(sqrt{Hp}N))

    可能比较卡空间,慎用STL

    然后这道题BZOJ上没有SPJ,面向数据编程可以知道:对于所有可行答案,取其中Atk最大的;对于所有Atk一样大的,取Def最大的。

    #include<bits/stdc++.h>
    //this code is written by Itst
    using namespace std;
    
    int read(){
    	int a = 0; char c = getchar();
    	while(!isdigit(c)) c = getchar();
    	while(isdigit(c)){
    		a = a * 10 + c - 48; c = getchar();
    	}
    	return a;
    }
    
    const int _ = 2e6 + 7;
    #define PII pair < int , int >
    struct node{
    	int nxt , rht , val;
    }now[_ * 5 + 5000];
    int head[_] , N , CA , CD , cnt , MXD;
    long long num[_] , Ans , HP , ATK , DEF , sum , X , Y , Z;
    
    void push(int rht , int val , int id){
    	now[++cnt] = (node){head[id] , rht , val};
    	head[id] = cnt;
    }
    
    void modify(int plc , int val){
    	num[plc] += val;
    	if(Y <= plc){sum += val; Z += (plc - Y) * val;}
    }
    
    int main(){
    	N = read(); CA = read(); CD = read();
    	for(int i = 1 ; i <= N ; ++i){
    		int h = read() - 1 , a = read() , d = read();
    		for(int j = 1 , pj ; j <= h ; j = pj + 1){
    			pj = h / (h / j);
    			if(j == 1) push(a , h + 1 , d + 1);
    			else push(a , h / j - h / (j - 1) , d + j);
    		}
    		push(a , -1 , h + d + 1);
    		MXD = max(MXD , d);
    	}
    	Ans = 1e18; Y = 1e6; Z = 1;
    	for(X = 1 ; X <= 2e6 ; ++X){
    		for(int i = head[X] ; i ; i = now[i].nxt)
    			modify(now[i].rht , now[i].val);
    		if(X <= MXD) continue;
    		while(Y > 1 && sum < CD){
    			Z += sum; sum += num[--Y];
    		}
    		if(Z + X * CA + Y * CD <= Ans){
    			Ans = Z + X * CA + Y * CD;
    			ATK = X; DEF = Y; HP = Z;
    		}
    	}
    	cout << HP << ' ' << ATK << ' ' << DEF;
    	return 0;
    }
    
  • 相关阅读:
    centos7 tar.gz zip 解压命令[转]
    centos7 下 安装visual studio code ,打开运行。
    yum提示Another app is currently holding the yum lock; waiting for it to exit...
    Linux CentOS7 安装
    虚拟机 centos7 的网络与电脑所在一个网络如何设置
    django创建web项目
    uwsgi Flask web.py
    MariaDB 与 MySQL 区别
    python pymysql 与 mysqlclient
    如何提高自己的象棋水平及象棋开局的五种忌讳
  • 原文地址:https://www.cnblogs.com/Itst/p/11110944.html
Copyright © 2011-2022 走看看