bzoj4518/luogu4072 征途(斜率优化dp)
首先推一波公式:
设f[t][i]为第t天以i为结尾,这时已经算了的最小公差$*m^2$
设s[i]为1到i的和
$$f[t][i]=min\{f[t-1][j]+m*(s[i]-s[j]-\frac{s[n]}{m})\}^2$$
$$f[t][i]=min\{f[t-1][j]+\frac{(s[n])^2}{m}-2s[n](s[i]-s[j])+m(s[i]-s[j])^2\}$$
因为一共有m段,每段中都加了个$\frac{(s[n])^2}{m}$,所以只要把它提出来,就能保证没有分数了
然后再推一波做斜率优化就好了
然而...:
一定要初始化t=1的情况!!!否则可能会出现f[1][x]不是从f[1][0]转移过来的情况!!!!很关键!!!!!!!!!!!
我太差了做的时候这都想不到
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define LL long long int 5 using namespace std; 6 const int maxn=3030; 7 8 int rd(){ 9 int x=0;char c=getchar(); 10 while(c<'0'||c>'9') c=getchar(); 11 while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar(); 12 return x; 13 } 14 15 LL m,n,s[maxn],f[maxn][maxn]; 16 int q[maxn],head,tail; 17 18 inline LL pw(LL x){return x*x;} 19 20 inline double slope(int t,int j1,int j2){ 21 return (double)(f[t][j1]+m*pw(s[j1])+2*s[n]*s[j1]-f[t][j2]-m*pw(s[j2])-2*s[n]*s[j2])/(s[j1]-s[j2]); 22 } 23 24 int main(){ 25 int i,j,k; 26 n=rd(),m=rd(); 27 for(i=1;i<=n;i++) s[i]=s[i-1]+rd(); 28 for(i=1;i<=n;i++) f[1][i]=m*pw(s[i]-s[j])-2*s[n]*(s[i]-s[j]); 29 for(k=2;k<=m;k++){ 30 q[head=tail=1]=k-1; 31 for(i=k;i<=n;i++){ 32 while(head<tail&&slope(k-1,q[head],q[head+1])<2*m*s[i]) head++; 33 j=q[head]; 34 f[k][i]=f[k-1][j]+m*pw(s[i]-s[j])-2*s[n]*(s[i]-s[j]); 35 while(head<tail&&slope(k-1,q[tail-1],q[tail])>slope(k-1,q[tail],i)) tail--; 36 q[++tail]=i; 37 } 38 }printf("%lld\n",f[m][n]+pw(s[n])); 39 }