征途
作者:互联网
虽然又是一遍AC的,但不得不说这题打得我好慌张,还调了十几分钟,虽然都是智障错误。
回归正题。猛然一看,n只有3000,貌似不要斜率优化耶。
但事实上,普通DP是N^2*M的,所以还是得斜率优化哈哈。
构造数列A1~Am,表示第i段的和。
方差乘m^2后长这样子:m*Ai^2-(Ai)^2
惊喜的发现(Ai)^2是个定值,那么我们只要使Ai^2最小即可。
就问你眼不眼熟?这不就是例一吗?但是此题多一维。
可以推导出状转方程:f[i][j]=min{f[k][j-1]+(sum[i]-sum[k])^2}
发现f[……][i]只跟f[……][i-1]有关,那就队列里放i-1的然后统计i的答案呗。
看代码:
#include<bits/stdc++.h> using namespace std; #define int long long const int maxn=3000+10; int n,m,f[maxn][maxn],sum[maxn],d[maxn],q[maxn]; int yval(int a,int b,int c){ return f[b][c]+sum[b]*sum[b]-f[a][c]-sum[a]*sum[a]; } int xval(int a,int b){return sum[b]-sum[a];} signed main(){ cin>>n>>m; for(int i=1;i<=n;i++){ scanf("%lld",&d[i]); sum[i]=sum[i-1]+d[i]; } //memset(f,0x3f,sizeof(f)); for(int i=1;i<=n;i++) f[i][1]=sum[i]*sum[i]; for(int i=2;i<=m;i++){ int l=1,r=1; q[l]=0; for(int j=1;j<=n;j++){ while(l<r&&yval(q[l],q[l+1],i-1)<=xval(q[l],q[l+1])*2*sum[j])l++; f[j][i]=f[q[l]][i-1]+(sum[j]-sum[q[l]])*(sum[j]-sum[q[l]]); //printf("%d %d %d %d %d\n",j,i,q[l],f[q[l]][i-1],f[j][i]); while(l<r&&yval(q[r-1],q[r],i-1)*xval(q[r],j)>=xval(q[r-1],q[r])*yval(q[r],j,i-1))r--; q[++r]=j; //printf("%d %d\n",l,r); } } //for(int i=1;i<=m;i++) // for(int j=1;j<=n;j++) // printf("f[%d][%d]=%d\n",j,i,f[j][i]); printf("%lld\n",m*f[n][m]-sum[n]*sum[n]); return 0; }
看到那一堆调试代码了吗?警醒读者:别把i和j弄反了!!!
标签:return,int,sum,Ai,maxn,征途,yval 来源: https://www.cnblogs.com/syzf2222/p/12386827.html