1. 程式人生 > >●BZOJ 4518 [Sdoi2016]征途

●BZOJ 4518 [Sdoi2016]征途

times iostream min problem return scanf 斜率優化dp body nbsp

題鏈:

http://www.lydsy.com/JudgeOnline/problem.php?id=4518

題解:

斜率優化DP

首先看看最後答案的形式:

設a[i]為第i天走的距離,那麽

$ANS=\frac{\sum_{i=1}^{M}(a[i]-\overline{x})^2}{M}\times{M^2}$

$\;\qquad=\frac{(\sum_{i=1}^{M}a[i]^2)-2\overline{x}SUM+M\overline{x}^2}{M}\times{M^2}$

$\;\qquad=M(\sum_{i=1}^{M}a[i]^2)-SUM^2$

由於M和SUM是固定的,所以問題轉化為求$\sum_{i=1}^{M}a[i]^2$的最小值,

即把區間分為M段,使得每一段的和的平方加起來最小。

定義 DP[i][j] 為前i個位置,分為了j段,且i位置為最後一段的結尾的最小值。

轉移:

$DP[i][j]\,=\,min(DP[k][j-1]+(SUM[i]-SUM[k])^2)$

然後把式子展開,得到:

$DP[i][j]\,=\,min(DP[k][j-1]+SUM[k]^2-2SUM[i]SUM[k]+SUM[i]^2)$

是一個典型的可以用斜率優化的式子。

(由於DP時是先枚舉第二維,一層一層地計算,所以以下的內容中省略掉dp的第二維,同時用g[i]表示上一層的dp[i][~])

令$Y[j]=g[j]+SUM[j]^2$,

若對於當前計算的dp[i],存在兩個轉移來源點 k,j,k < j,且j優於k

則得到

$Y[j]-2SUM[i]SUM[j]-Y[k]-2SUM[i]SUM[k]<0$

化簡:$\frac{Y[j]-Y[k]}{2SUM[j]-2SUM[k]}<SUM[i]$

令Slope(j,k)=$\frac{Y[j]-Y[k]}{2SUM[j]-2SUM[k]}$,

則得到結論:若k < j,且Slope(j,k)<SUM[i],則j優於k。

那麽如果存在 k<j<i,且Slope(i,j)<Slope(j,k),則j是無效點,舍去。

同時註意到SUM[i]單增,所以可以用單調隊列維護。

最終的復雜度 O(N*M)

代碼:

#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 3050
using namespace std;
int DP[2][MAXN],SUM[MAXN];
int N,M,*t1=DP[0],*t2=DP[1];
struct Moque{
	int q[MAXN],l,r;
	void Reset(){l=r=1; q[1]=0; t2[0]=0;}
	double Y(int j){
		return t2[j]+1.0*SUM[j]*SUM[j];
	}
	double X(int j){
		return 2.0*SUM[j];
	}
	double Slope(int j,int k){
		return (Y(j)-Y(k))/(X(j)-X(k));
	}
	void Push(int i){
		if(l<=r&&SUM[i]==SUM[q[r]]) 
			{if(t2[i]<t2[q[r]]) r--; else return;}
		while(l+1<=r&&Slope(i,q[r])<Slope(q[r],q[r-1])) r--;
		q[++r]=i;
	}
	int Query(int i){
		while(l+1<=r&&Slope(q[l],q[l+1])<SUM[i]) l++;
		return q[l];
	}
}Q;
int main(){
	scanf("%d%d",&N,&M);
	for(int i=1;i<=N;i++)
		scanf("%d",&SUM[i]),SUM[i]+=SUM[i-1];
	memset(DP,0x3f,sizeof(DP));
	t1[0]=0;
	for(int j=1;j<=M;j++){
		Q.Reset(); swap(t1,t2);
		for(int i=1,k;i<=N;i++){
			Q.Push(i); k=Q.Query(i);
			t1[i]=t2[k]+(SUM[i]-SUM[k])*(SUM[i]-SUM[k]);
		}
	}
	printf("%d",M*t1[N]-SUM[N]*SUM[N]);
	return 0;
}

  

●BZOJ 4518 [Sdoi2016]征途