P4767 IOI2000 邮局

(n) 个村庄,给出了他们的横坐标。现在要在这些村庄中的一些村庄安放 (p) 个邮局,要求算每个村庄和最近的邮局之间所有距离的最小可能的总和。

(50\%:sim70\%)

悄咪咪告诉你,开氧可以跑(90pts!!!!!!!!!!) 这还打啥正解

(f[i][j])表示前(i)个村庄放(j)个邮局最小距离和

(w[i][j])表示村庄区间([i,j])内放(1)个邮局的距离和

(w)可以预处理出来,放置一个邮局,邮局位置总是在中位数处

(w[l][r]=w[l][r-1]+X[r]-X[frac{l+r}2]) (V^2)递推

(f[i][j]=min{f[k][j-1]+w[k+1][j])}~~kin[0,i))

复杂度(O(PV^2))

const int N = 3005;
int V,P,x[N],w[N][N],f[N][305];
inline int min(int a,int b){return a < b ? a : b;}
void init(){
	for(re int i = 1;i <= V;++i) x[i] = read();
	for(re int i = 1;i <= V;++i)
		for(re int j = i+1;j <= V;++j)
			w[i][j] = w[i][j-1] + x[j] - x[i+j>>1];
}
int main(){
	V = read(); P = read();
	init();
	memset(f,0x3f,sizeof(f));
	f[0][0] = 0;
	for(re int j = 1;j <= P;++j)
		for(re int i = 1;i <= V;++i)
			for(re int k = 0;k < i;++k)
				f[i][j] = min(f[k][j-1] + w[k+1][i],f[i][j]);
	printf("%d",f[V][P]);
}

(100\%:)

(w)其实是满足四边形不等式的

由递推式可得(w[l][r+1]-w[l][r]=X[r+1]-X[frac{l+r+1}2]~~①)

[w[l+1][r+1]-w[l+1][r]=X[r+1]-X[frac{l+r+2}2]~~②\ ①-②\ =X[frac{l+r+2}2]-X[frac{l+r+1}2]\ ]

(X)递增,则(large X[frac{l+r+2}2]-X[frac{l+r+1}2]ge0)

[w[l][r+1]-w[l][r]-(w[l+1][r+1]-w[l+1][r])ge0\ w[l][r+1]-w[l][r]-w[l+1][r+1]+w[l+1][r]ge0\ w[l][r+1]+w[l+1][r]ge w[l][r]+w[l+1][r+1] ]

显然(w)满足四边形不等式,且对于(ale ble cle d)(w[a][d]ge w[b][c])(dp)满足四边形不等式

所以对于(f[i][j])决策,(f[i][j-1]le f[i][j]le f[i+1][j])

(s[i][j])(i)之前建(j)个邮局的最优决策

所以转移(f[i][j])时,从([s[i][j-1],s[i+1][j]])中找最优决策

因为要用到(f[i+1][j]),所以倒叙枚举(i)

(O(PV))

int V,P,x[N],w[N][N],f[N][305],s[N][305];
void init(){
	for(int i = 1;i <= V;++i) x[i] = read();
	for(int i = 1;i <= V;++i)
		for(int j = i+1;j <= V;++j)
			w[i][j] = w[i][j-1] + x[j] - x[i+j>>1];
}
int main(){
	V = read(); P = read();
	init();
	memset(f,0x3f,sizeof(f));
	f[0][0] = 0;
	for(int j = 1;j <= P;++j){
		s[V + 1][j] = V;
		for(int i = V;i >= 1;--i){ 
			int minn = 0x3f3f3f3f,minid;
			for(int k = s[i][j-1];k <= s[i+1][j];++k){
				if(f[k][j-1] + w[k+1][i] < minn){
					minn = f[k][j-1] + w[k+1][i];
					minid = k;
				}
			}
			f[i][j] = minn; s[i][j] = minid;	
		} 
	}
	printf("%d",f[V][P]);
}
原文地址:https://www.cnblogs.com/shikeyu/p/13822303.html