gmoj 6845. 【2020.11.02提高組模擬】梯度彌散
阿新 • • 發佈:2020-11-03
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; }