题解 P4767 【[IOI2000]邮局】
思路
首先将坐标排个序。
定义
易得
那么关键就在于
基本的数学知识,若村庄数为奇数,放中位数处距离和最小。若村庄为偶数,放中间两个村庄之间任意一处均可。
于是便可得一个
#include<bits/stdc++.h>
#define MAXN 3010
#define N 310
using namespace std;
int V,P,X[MAXN],dp[MAXN][N];
int w(int l,int r) {
int mid=l+r>>1,ans=0;
for(int i=l;i<mid;i++) ans+=X[mid]-X[i];
for(int i=mid+1;i<=r;i++) ans+=X[i]-X[mid];
return ans;
}
int main() {
cin>>V>>P;
for(int i=1;i<=V;i++) cin>>X[i];
sort(X+1,X+V+1);
memset(dp,0x3f,sizeof(dp));
dp[0][0]=0;
for(int j=1;j<=P;j++) {
for(int i=1;i<=V;i++) {
for(int k=0;k<i;k++) {
dp[i][j]=min(dp[k][j-1]+w(k+1,i),dp[i][j]);
}
}
}
cout<<dp[V][P]<<endl;
return 0;
}
再想想,可以提前预处理出
于是又可以得到一个
#include<bits/stdc++.h>
#define MAXN 3010
#define N 310
using namespace std;
int V,P,X[MAXN],dp[MAXN][N],w[MAXN][MAXN];
void init() {
for(int l=1;l<=V;l++) {
w[l][l]=0;
for(int r=l+1;r<=V;r++) {
w[l][r]=w[l][r-1]+X[r]-X[l+r>>1];
}
}
}
int main() {
cin>>V>>P;
for(int i=1;i<=V;i++) cin>>X[i];
init();
sort(X+1,X+V+1);
memset(dp,0x3f,sizeof(dp));
dp[0][0]=0;
for(int j=1;j<=P;j++) {
for(int i=1;i<=V;i++) {
for(int k=0;k<i;k++) {
dp[i][j]=min(dp[k][j-1]+w[k+1][i],dp[i][j]);
}
}
}
cout<<dp[V][P]<<endl;
return 0;
}
其实
由上面
那么
用①
即
因此
因为
于是状态转移
由于要用到
时间复杂度
代码
#include<bits/stdc++.h>
#define MAXN 3010
#define N 310
#define INF 0x3f3f3f3f
using namespace std;
int V,P,X[MAXN],dp[MAXN][N],w[MAXN][MAXN],d[MAXN][N];
void init() {
for(int l=1;l<=V;l++) {
w[l][l]=0;
for(int r=l+1;r<=V;r++) {
w[l][r]=w[l][r-1]+X[r]-X[l+r>>1];
}
}
}
int main() {
cin>>V>>P;
for(int i=1;i<=V;i++) cin>>X[i];
init();
sort(X+1,X+V+1);
memset(dp,0x3f,sizeof(dp));
dp[0][0]=0;
for(int j=1;j<=P;j++) {
d[V+1][j]=V;
for(int i=V;i>=1;i--) {
int minn=INF,minid;
for(int k=d[i][j-1];k<=d[i+1][j];k++) {
if(dp[k][j-1]+w[k+1][i]<minn) {
minn=dp[k][j-1]+w[k+1][i];
minid=k;
}
}
dp[i][j]=minn;
d[i][j]=minid;
}
}
cout<<dp[V][P]<<endl;
return 0;
}