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