1. 程式人生 > >bzoj4518: [Sdoi2016]征途

bzoj4518: [Sdoi2016]征途

化簡 class freopen print log style long 征途 ont

第一眼看到這題的想法:這不就是一題傻逼DP嗎。。。水經驗

然而……誒誒誒DP怎麽寫

%了題解(還被嘲諷%題解比自己AC還多)原來是式子化簡錯了(囧orz,所以我不化簡給你),菜啊。

然後寫個斜率優化就行(懶得滾)。。記得開LL(搞得都不知道什麽時候開了)

/*
k1<k2 且 k2優於k1

f[k1][j-1]+(s[i]-s[k1])*(s[i]-s[k1])  >=   f[k2][j-1]+(s[i]-s[k2])*(s[i]-s[k2])

f[k1][j-1]-2*s[i]*s[k1]+s[k1]^2  >=   f[k2][j-1]-2*s[i]*s[k2]+s[k2]^2

f[k1][j-1]-2*s[i]*s[k1]+s[k1]^2  >=   f[k2][j-1]-2*s[i]*s[k2]+s[k2]^2

( f[k1][j-1]+s[k1]^2 ) - ( f[k2][j-1]+s[k2]^2 ) >=  2*s[i]*s[k1]-2*s[i]*s[k2]

( f[k1][j-1]+s[k1]^2 ) - ( f[k2][j-1]+s[k2]^2 ) / (s[k1]-s[k2]) <= 2*s[i]
*/ #include<cstdio> #include<iostream> #include<cstring> using namespace std; typedef long long LL; int a[3100],s[31000],list[3100]; LL f[3100][3100]; LL X(int k,int j) { return f[k][j-1]+s[k]*s[k]; } int Y(int k) { return s[k]; } double slope(int k1,int k2,int j) {
return double(X(k1,j)-X(k2,j)) / double(Y(k1)-Y(k2)); } int main() { freopen("journey.in","r",stdin); freopen("journey.out","w",stdout); int n,m,sum=0; scanf("%d%d",&n,&m); s[0]=0;for(int i=1;i<=n;i++) { scanf("%d",&a[i]); s[i]=s[i-1]+a[i]; sum
+=a[i]; f[i][1]=s[i]*s[i]; } for(int j=2;j<=m;j++) { int head=1,tail=1; list[1]=j-1; for(int i=j;i<=n;i++) { while(head<tail&&slope(list[head],list[head+1],j)<=2*s[i])head++; int x=list[head]; f[i][j]=f[x][j-1]+(s[i]-s[x])*(s[i]-s[x]); while(head<tail&&slope(list[tail-1],list[tail],j)>slope(list[tail],i,j))tail--; list[++tail]=i; } } printf("%lld\n",f[n][m]*m-sum*sum); return 0; }

bzoj4518: [Sdoi2016]征途