BZOJ 1237 配对(DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1237

题意:给出两个n元素的数列A和B。为A中的每个元素在B中为其找一个配对的元素(配对的元素不能相等,B中每个元素只能被使用一次),使得所有配对的两个数的差的绝对值之和最小?

思路:首先排序,若无配对元素不能相等这一 限制,则排序后一一匹配即可。有了这个限制,那么对于相等的元素就要在其前后进行调整,显然,与距离较远的调整不如与距离近的调整优。那么,需要在多大的 范围内调整才能保证最优呢?大牛给出的结论是最多在上下三个元素内调整即可。我不会证明。。不过,两个肯定是不行的,比如n=3,三个元素均对应相等,此 时必须要三个元素之间调整。那么,若4个连续元素对应相等呢?此时前两个调整后两个调整即可得到最优。因此用不着四个调整。这只是我粗糙的理解。这样的话 DP即可。f[i]表示前i个元素匹配完的最优值。

i64 f[N];
int a[N],b[N],n;

i64 C(int x)
{
    if(x==0) return inf;
    return abs(x);
}

int main()
{
    RD(n);
    int i;
    FOR1(i,n) RD(a[i],b[i]);
    sort(a+1,a+n+1);
    sort(b+1,b+n+1);
    f[1]=C(a[1]-b[1]);
    f[2]=min(f[1]+C(a[2]-b[2]),C(a[1]-b[2])+C(a[2]-b[1]));
    for(i=3;i<=n;i++)
    {
        f[i]=f[i-1]+C(a[i]-b[i]);
        f[i]=min(f[i],f[i-2]+C(a[i]-b[i-1])+C(a[i-1]-b[i]));
        f[i]=min(f[i],f[i-3]+min(C(a[i]-b[i-1])+C(a[i-1]-b[i-2])+C(a[i-2]-b[i]),
                                 C(a[i]-b[i-2])+C(a[i-1]-b[i])+C(a[i-2]-b[i-1])));
    }
    if(f[n]>=inf) puts("-1");
    else PR(f[n]);
}

BZOJ 1237 配对(DP),布布扣,bubuko.com

时间: 2024-08-07 04:33:09

BZOJ 1237 配对(DP)的相关文章

bzoj 1237 配对

Written with StackEdit. Description 你有\(n\) 个整数\(A_i\)和\(n\) 个整数\(B_i\).你需要把它们配对,即每个\(A_i\)恰好对应一 个\(B_i\).要求所有配对的整数差的绝对值之和尽量小,但不允许两个相同的数配对.例如\(A=\){\(5,6,8\)},\(B=\){\(5,7,8\)},则最优配对方案是\(5\)配\(8\), \(6\)配\(5\), \(8\)配\(7\),配对整数的差的绝对值分别为\(2, 2, 1\),和为

【BZOJ1786】[Ahoi2008]Pair 配对 DP

[BZOJ1786][Ahoi2008]Pair 配对 Description Input Output Sample Input 5 4 4 2 -1 -1 3 Sample Output 4 题解:结论!!!为了使逆序对最少,我们在-1位置填入的数一定是单调不减的.(可以用反证法证明,很简单.) 所以DP,我们用f[i][j]表示枚举到第i个数,上一个在-1位置填入的数是j个最少逆序对个数.然后转移也很简单~ #include <cstdio> #include <cstring&g

bzoj 1597 斜率DP

1597: [Usaco2008 Mar]土地购买 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 5115  Solved: 1897[Submit][Status][Discuss] Description 农夫John准备扩大他的农场,他正在考虑N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足(1 <= 宽 <= 1,000,000; 1 <= 长 <= 1,000,000). 每块土地

bzoj 3668 数位DP

收获: 1.如果有很多位操作,并且不包含+-×/等高级运算,那么可以一位一位考虑,如果求一个最优解,可以尝试逐位确定,这道题因为原始攻击值有范围,那么就需要数位DP. 1 /************************************************************** 2 Problem: 3668 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:288 ms 7 Memory:804 kb 8 **

bzoj 1017 tree dp

这道题几经波折啊. 最开始和vfleaking一样,把题意理解错了,认为一个装备可能被多个装备依赖,然后想不出来,去看题解. 发现自己理解错了题意,自己想想,其实也不难想到dp[i][j][k]表示“i号节点代表的子树,用掉j的钱,给父亲预留k个自己(但还是父亲付钱)”的状态,写出来交上去就是T, 开始以为是常数问题,优化半天还是T,看了他人AC代码,才发现自己算法有一定问题:重复计算了很多东西. 树形动规,一般在大的树规下,每个节点还会对儿子们来一次”资源分配“,一般是用背包解决,这道题也是这

BZOJ 1996 合唱队(DP)

考虑从最后的队形开始依次还原最初的队形. 对于当前的队形,要么选最左边的,要么选最右边的. 如果选了左边的,那么下次选择的一定是大于它的.右边的同理. 所以定义dp[mark][l][r]为区间[l,r]的选择状态为mark的方法数. 然后记忆化搜索一下就可以了. # include <cstdio> # include <cstring> # include <cstdlib> # include <iostream> # include <vect

BZOJ 1833 数位DP

思路: 数位DP f[i][j][k]表示走到第i位 开头位j 数字k 出现的次数 $f[i][j][k]+=f[i-1][l][k];$$f[i][j][j]+=base[i]$ calc的时候要有特殊的技巧...(我看题解学会的) //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define int long long int

BZOJ 4321: queue2( dp )

dp(i, j, 1)表示前i个, 有j对是不合法的, i和i-1是在一起的. dp(i, j, 0)表示前i个, 有j对是不合法的, i和i-1不在一起的. 转移我们只需考虑是多了一对不合法的还是少了一对不合法的, 或者是不变, 考虑当前i和i-1,i-2的位置的影响就可以了. dp(i, j, 1) = 2*dp(i-1, j-1, 0) + dp(i-1, j-1, 1) + dp(i-1, j, 1) dp(i, j, 0) = (i-j-2)*dp(i-1, j, 0) + (j+1)

BZOJ 1068 (区间DP)

题意:字符串的压缩,f[l][r][0]代表还没M,f[l][r][1]代表有M. 1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 #include<algorithm> 5 #include<iostream> 6 int f[55][55][2],n; 7 char s[555]; 8 bool ok(int l,int r){ 9 int len=(r-l+1)/2; 1