gmoj 6845. 【2020.11.02提高组模拟】梯度弥散

6845. 【2020.11.02提高组模拟】梯度弥散

Solution

考虑二分答案

二分后直接贪心操作

但暴力操作的话时间复杂度\(O(nk\ \cdot log(V))\)显然无法接受

考虑差分


c=0与c=1的情况都很好做,

伤害\(\left\{\begin{matrix} c=0:1\\ c=1:(x+i)-j \end{matrix}\right.\)

其中i是刚开始攻击的位置,j为当前处理的位置

此时考虑c=2的情况(有多种方法,这里介绍一种)

此时伤害值可以表示为$(x+i-j)^2

\((x+i-j)^2=(x+i)^2\cdot j^0-2\cdot j\cdot(x+i)+j^2\)

我们可以分别差分维护变量前面的系数

这种维护方法也可以推广到维护c=0及c=1的情况

完结撒花

Code

#include <cstdio>
#define N 100010
#define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
using namespace std;
int num,n,c,k,i,j,l,r,mid,ans,last,add,s[N],a[4];
long long t,b[N][4];
int min(int x,int y){return x<y?x:y;}
int main()
{
    open("dispersion");
    scanf("%d%d%d%d",&num,&n,&c,&k);
    for (i=1;i<=n;i++)
        scanf("%d",&s[i]);
    l=0;r=100000;
    while (l<r)
    {
        mid=(l+r)/2;ans=0;
        a[0]=a[1]=a[2]=0;
        for (i=1;i<=n;i++)
        {
        	t=s[i];
            for (j=0;j<=2;j++)
                a[j]+=b[i][j],b[i][j]=0;
            t-=a[0]+a[1]*i+a[2]*i*i;
            if (t<=0) continue;
            add=min(i+mid+1,n+1);
            if (!c)
            {
            	last=t;
                b[add][0]-=last;
                a[0]+=last;
            }
            if (c==1)
            {
            	last=t/(mid)+(t%(mid)!=0);
                b[add][0]-=1ll*(i+mid)*last;
                b[add][1]+=last;
                a[0]+=1ll*(i+mid)*last;
                a[1]-=last;
            }
            if (c==2)
            {
            	last=t/(mid*mid)+(t%(mid*mid)!=0);
                b[add][0]-=1ll*last*(i+mid)*(i+mid);
                b[add][1]+=1ll*2*(i+mid)*last;
                b[add][2]-=last;
                a[0]+=1ll*last*(i+mid)*(i+mid);
                a[1]-=1ll*2*(i+mid)*last;
                a[2]+=last;
            }
            ans+=last;
        }
        if (ans<=k) r=mid;else l=mid+1;
    }
    if (l==100000) printf("-1");else printf("%d",r);
    return 0;
}
posted @ 2020-11-03 21:15  Sport_River  阅读(132)  评论(0编辑  收藏  举报