洛谷 P1485 火枪打怪

Posted 殇雪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P1485 火枪打怪相关的知识,希望对你有一定的参考价值。

题目描述

LXL进入到了一片丛林,结果他发现有n只怪物排成一排站在他面前。LXL有一杆火枪能对付这些怪物。他知道从左至右数第i只怪物的血量是mi。现在LXL可以将一些子弹射向某个怪物。LXL可以控制他所发射的子弹数量及子弹的威力值。当某个子弹射到第i个怪物,如果这个子弹的威力值为p,除了这个怪物会掉p点血以外,它左边的第j个怪物(j<i),也会遭到Max(0, p - (i - j) * (i - j))的溅射伤害(好神奇的子弹)。当某只怪物的血量小于0时,它就死了,但它的尸体还在,即怪物的位置永远不会改变。LXL希望只用k发子弹,请你求出一个最小的正整数p,使LXL用k发子弹且每发子弹的威力值为p就可以消灭所有怪物。

SOL

我们显然可以发现这道题的二分性质。再细心观摩一波数据,50W,只能用O(nlogn)及以下的算法。二分需要一个log,这便要求我们O(n)处理check函数。

比较显然,我们可以差分。我们发现只有右边对左边有贡献,不妨从右到左做,我们发现这是一个二次多项式,那么可以二阶差分,对于单一的子弹来说,他的

伤害的差分是一个等差数列,K=2n-1,那对差分数组进行差分,我们统计对当前怪物有贡献的子弹,那么这个伤害的二阶差分就是两倍的子弹数。那么我们还

有一个问题,那就是子弹的伤害不可能是负数。我们有这样一个方法,我们在一颗子弹的伤害区域的最左侧打标记  -1,标示该位置之后出子弹范围,那么我们同

时在一阶差分数组中把多余的伤害减掉,那么这颗子弹之后就没有贡献了。

#include<bits/stdc++.h>
#define sight(c) (‘0‘<=c&&c<=‘9‘)
#define LL long long
inline void read(int &x) {
    static char c;
    for (;!sight(c);c=getchar());
    for (x=0;sight(c);c=getchar())x=x*10+c-48;
}
inline void read(long long &x) {
    static char c;static int b;
    for (b=1;!sight(c);c=getchar())if (c==-) b=-1;
    for (x=0;sight(c);c=getchar())x=x*10+c-48;
    x*=b;
}
#define N 501007
#define min(a,b) (a)<(b)?(a):(b)
#define HP a
LL len,ans2,ans,Ans,cm,n,dle,a[N],k,r,c1[N],c2[N],c3[N],c4[N],hp[N];
bool check(LL P)
{
    int sss=sqrt(P); int tot=0;
    LL t1=0,t2=0,t3=0,t0=0;
    memset(c1,0,sizeof(c1)); memset(c2,0,sizeof(c2));
    memset(c3,0,sizeof(c3)); memset(c4,0,sizeof(c4));
    for(int i=1;i<=n;++i)hp[n-i+1]=HP[i]+1;//记得+1,因为怪物0血还没有死
    for(int i=1;i<=n;++i)
    {
        t3+=c3[i]; t2+=c2[i];
        t1+=c1[i]+t2; t0+=t1+c4[i];
        hp[i]-=1ll*P*t3-t0;
        if(hp[i]<=0)continue; int gg=((hp[i]+P-1)/P);
        tot+=gg; if(tot>k)return false;
        c3[i+1]+=gg;c3[min(n+1,i+sss+1)]-=gg;
        c2[i+1]+=1ll*2*gg;c2[min(n+1,i+sss+1)]-=2*gg;
        c1[i+1]-=gg;c1[min(n+1,i+sss+1)]-=1ll*(1ll*2*sss-1)*gg;
        c4[min(n+1,i+sss+1)]-=1ll*sss*sss*gg;
    }
    return tot<=k;
}
int main () {
    read(n); read(k);
    for (int i=1;i<=n;i++) read(a[i]);
    r=1ll<<53;
    while (r) {
        if (!check(ans+r)) ans+=r;
        r>>=1;
    } 
    printf("%lld\n",ans+1); return 0;
}

 

以上是关于洛谷 P1485 火枪打怪的主要内容,如果未能解决你的问题,请参考以下文章

火枪打怪

流星蝴蝶剑怎么加电脑人啊??

关乎DevOps成败的三个火枪手

Flask连接数据库打怪升级之旅

Flask连接数据库打怪升级之旅

Flask连接数据库打怪升级之旅