队列维护下凸包裸题
式子不太好推,但其实不用把式子全展开的.....
k单调递增,x单调递增,队列维护一下就行了
因为f[i]期望最小值,所以维护下凸包
好像记录一下凸包的坐标能减少常数
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #define il inline 5 #define ll long long 6 #define N 51000 7 using namespace std; 8 int n,que[N]; 9 ll L,f[N],c[N],s[N]; 10 int gc() 11 { 12 int rett=0,fh=1;char c=getchar(); 13 while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();} 14 while(c>='0'&&c<='9'){rett=(rett<<3)+(rett<<1)+c-'0';c=getchar();} 15 return rett*fh; 16 } 17 il ll yy(ll j){return f[j]+2ll*(s[j]+j)*(1ll+L)+(s[j]+j)*(s[j]+j)+(1ll+L)*(1ll+L);} 18 il ll xx(ll j){return s[j]+j;} 19 il ll kk(ll i){return 2ll*(s[i]+i);} 20 21 int main() 22 { 23 n=gc(),L=gc(); 24 for(int i=1;i<=n;i++) c[i]=gc(); 25 for(int i=1;i<=n;i++) s[i]=s[i-1]+c[i]; 26 int hd=1,tl=1; 27 for(ll i=1;i<=n;i++) 28 { 29 while(hd+1<=tl&&yy(que[hd])-kk(i)*xx(que[hd])>=yy(que[hd+1])-kk(i)*xx(que[hd+1])) 30 hd++; 31 f[i]=yy(que[hd])-kk(i)*xx(que[hd])+(s[i]+i)*(s[i]+i)-2ll*(s[i]+i)*(1ll+L); 32 while(hd+1<=tl&&(yy(i)-yy(que[tl]))*(xx(que[tl])-xx(que[tl-1])) <= (yy(que[tl])-yy(que[tl-1]))*(xx(i)-xx(que[tl]))) 33 tl--; 34 que[++tl]=i; 35 } 36 printf("%lld ",f[n]); 37 return 0; 38 }