1. 程式人生 > 實用技巧 >gmoj 6845. 【2020.11.02提高組模擬】梯度彌散

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>
#include <algorithm>
#include <cstring>
#include <cmath>
#define N 4000001
#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,s[N];
long long a[4],b[N][4],t[N];
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;
        for (i=1;i<=n;i++)
            t[i]=s[i];
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        for (i=1;i<=n;i++)
        {
            for (j=0;j<=2;j++)
                a[j]+=b[i][j];
            t[i]-=a[0]+a[1]*i+a[2]*i*i;
            if (t[i]<=0) continue;
            if (!c)
            {
            	last=t[i];
                b[i][0]+=last;
                b[i+mid+1][0]-=last;
                a[0]+=last;
            }
            if (c==1)
            {
            	last=ceil((1.0*t[i])/mid);
                b[i][0]+=1ll*(i+mid)*last;
                b[i+mid+1][0]-=1ll*(i+mid)*last;
                b[i][1]-=last;
                b[i+mid+1][1]+=last;
                a[0]+=1ll*(i+mid)*last;
                a[1]-=last;
            }
            if (c==2)
            {
            	last=ceil((1.0*t[i])/(mid*mid));
                b[i][0]+=1ll*last*(i+mid)*(i+mid);
                b[i+mid+1][0]-=1ll*last*(i+mid)*(i+mid);
                b[i][1]-=1ll*2*(i+mid)*last;
                b[i+mid+1][1]+=1ll*2*(i+mid)*last;
                b[i][2]+=last;
                b[i+mid+1][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;
}