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 }

 

posted @ 2018-08-10 20:58  Ressed  阅读(145)  评论(0编辑  收藏  举报