 /**//*
題意:在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;
}
|