 /**//*
题意:在M个数中来匹配另外N个,权为|x-y| 问最小代价 M<10^5 N<2000
先排序,对于最后的匹配结果,不会出现交叉的情况 就可以做DP了
dp[i,j] = min(dp[i,j-1],dp[i-1,j-1]+|x-y|);
这样子是O(NM)的,会TLE
对于最优的情况,与Bi匹配的Aj 肯定不会有|ii-j|>N的 ii为A[]中最接近Bi的
所以对每个Bi 找到最接近Bi的Aj 然后只计算它左右各N个

这样确定了计算范围的,要注意从i-1过渡到i时取值时(dp[i-1])不要越出范围[beg,end]
*/
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

int dp[2][100005];
int A[100005],B[2010];

int main()
  {
//freopen("in","r",stdin);
for(int N,M;~scanf("%d%d",&M,&N);)
 {
for(int i=0;i<M;i++)
scanf("%d",&A[i]);
for(int i=0;i<N;i++)
scanf("%d",&B[i]);

sort(A,A+M);
sort(B,B+N);
int pos=0;
int beg,end,lbeg=0,lend=0;
int pre=1,now=0;
dp[pre][0]=0;

for(int i=0;i<N;i++)
 {
while(pos<M&&A[pos]<=B[i])pos++;
pos--;
beg=max(i,pos-N);
end=min(pos+N,M-1);
int jj=min(beg-1,lend);
jj=max(jj,lbeg);//也不能小于beg
dp[now][beg]=dp[pre][jj]+abs(A[beg]-B[i]);
//printf("%d ",dp[now][beg]);
for(int j=beg+1;j<=end;j++)
 {
int jj=min(j-1,lend);
dp[now][j]=min(dp[now][j-1],dp[pre][jj]+abs(A[j]-B[i]));
//printf("%d ",dp[now][j]);
}
//puts("");
lbeg=beg;
lend=end;
swap(pre,now);
}
printf("%d\n",dp[pre][lend]);
}
return 0;
}
|