HDU 6469 /// 二分

题目大意:

分裂怪有1到n种等级,

第1级的分裂怪称为原子怪,它不会分裂,被击杀时会产生a[1]点经验;

而第k级的分裂怪死亡时则会分裂成a[k]个第k - 1级的分裂怪。

一个体力可以杀死一个怪物。

q个询问,每次给定一个总体力值,求最多能获得多少经验

 

二分消灭的1级怪的个数,不断向上合并,能达到n级怪就是可行的

合并中应该向上取整

假设 1个i级怪会分裂成3个i+1级怪,此时若i+1级怪消灭了5个,则至少应消灭2个i级怪

若有连续很多级别的怪物只会分裂成1个怪物 那么就会出现一条长链 

把这一整条长链合并成一个点 记录下这个点离合并了多少个点就可以计算体力值的耗费了

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long
#define inc(i,j,k) for(int i=j;i<=k;i++)
#define dec(i,j,k) for(int i=j;i>=k;i--)
#define gcd(i,j) __gcd(i,j)
#define mem(i,j) memset(i,j,sizeof(i))
const int N=1e5+5;
const int mod=1e9+7;

int n,q,tot;
LL v[N],s[N];

bool check(LL m,LL w) {
    int sum=n; // 还需要消灭sum个级别的怪物才能获得经验
    inc(i,1,tot) {
        if(m==1) return (w-sum)>=0;
        // 在消灭低级怪M个的基础上
        // 此时必须消灭当前级别的m个怪物
        // 剩余体力还有w 到第n级还有sum个级别
        sum-=v[i]; w-=m*v[i];
        if(i<tot) m=m/s[i+1]+(m%s[i+1]==0 ? 0:1); // 向上取整
        if(w<0) return 0; // 体力不够 无解
    }
    return 1;
}

int main()
{
    scanf("%d%d",&n,&q);
    tot=1; v[tot]=1LL;
    scanf("%lld",&s[tot]);
    inc(i,2,n) {
        LL t; scanf("%lld",&t);
        if(t==1) v[tot]++;
        else v[++tot]=1, s[tot]=t;
        // 把只能分裂1个低级怪的怪物链合起来
    }
    while(q--) {
        LL w; scanf("%lld",&w);
        LL L=0,R=(LL)1e9,ans=0;
        while(L<=R) {
            LL M=(L+R)>>1;
            if(check(M,w)) ans=M, L=M+1;
            else R=M-1;
        } // 二分一共能打倒的一级怪的个数
        printf("%lld\n",ans*s[1]);
    }

    return 0;
}
View Code

 

posted @ 2019-03-19 17:49  _Jessie  阅读(255)  评论(0编辑  收藏  举报