Description

你有\(n\)个整数\(A_{i}\)和\(n\)个整数\(B_{i}\)。你需要把它们配对,即每个\(A_{i}\)恰好对应一 个\(Bp_{i}\)。要求所有配对的整数差的绝对值之和尽量小,但不允许两个相同的数配对。例如\(A=\lbrace 5,6,8 \rbrace\),\(B=\lbrace 5,7,8 \rbrace\),则最优配对方案是\(5\)配\(8\),\(6\)配\(5\),\(8\)配\(7\),配对整数的差的绝对值分别为\(2, 2, 1\),和为\(5\)。注意,\(5\)配\(5\),\(6\)配\(7\),\(8\)配\(8\)是不允许的,因为相同的数不许配对。

Input

第一行为一个正整数\(n\),接下来是\(n\)行,每行两个整数\(A_{i}\)和\(B_{i}\),保证所有\(A_{i}\)各不相同,\(B_{i}\)也各不相同。

Output

输出一个整数,即配对整数的差的绝对值之和的最小值。如果无法配对,输出\(-1\)。

Sample Input

3

3 65

45 10

60 25

Sample Output

32

HINT

\(30\%\)的数据满足:\(n \le 10^{4}\)

\(100\%\)的数据满足:\(1 \le n \le 10^{5}\),\(A_{i}\)和\(B_{i}\)均为\(1\)到\(10^{6}\)之间的整数。

难得又一道自己想出的题目。

首先如果没有相同的数字不能同时配对,那么排序之后两两配对一定是最优的。那么我们在满足题目限制一定也要尽可能的满足题目的限制,相邻两个进行交换。

我们令\(pos_{i}\)表示前第\(i\)个排序后数字相同配对的位置,\(f_{i,0/1}\)表示前\(i\)个数字相同的配对,使其合法的最小增加代价(\(0\)表示与前面的交换,\(1\)表示与后面的交换)。转移有这样以下的几个:

\[f_{i,1} = min(f_{i-1,0},f_{i-1,1})+calc(pos_{i},pos_{i}+1)
\]

当\(pos_{i-1} \ge pos_{i}-1\)时$$f_{i,0} = f_{i-1,0}+calc(pos_{i}-1,pos_{i})$$

否则$$f_{i,0} = min(f_{i-1,0},f_{i-1,1})+calc(pos_{i}-1,pos_{i})$$

产生分歧的原因是如果\(pos_{i-1} \ge pos_{i}-1\),那么如果\(i-1\)号非法配对与右边的交换,\(i\)号与左边的交换代价计算就会出错。

当\(i \ge 2\)并且\(pos_{i}=pos_{i-1}+1\),我们可以两个非法的进行交换,得到以下的转移:

当\(pos_{i-2} \ge pos_{i-1}-1\)时,$$f_{i,0} = min(f_{i,0},f_{i-2,0}+calc(pos_{i-1},pos_{i}))$$

否则$$f_{i,0} = min(f_{i,0},min(f_{i-2,0},f_{i-2,1})+calc(pos_{i-1},pos_{i}))$$

分歧的原因同上。

以上转移\(calc(a,b)\)为计算交换\(a,b\)位置增加代价的函数。

#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std; typedef long long ll;
#define inf (1LL<<60)
#define maxn 100010
int n,pos[maxn],tot; ll sum,A[maxn],B[maxn],f[maxn][2]; inline ll calc(int a,int b)
{
if (!a||!b) return inf; if (a > n||b > n) return inf;
return (abs(A[a]-B[b])+abs(A[b]-B[a]))-(abs(A[a]-B[a])+abs(A[b]-B[b]));
}
inline void dp()
{
memset(f,0x7,sizeof(f));
f[0][0] = f[0][1] = 0;
for (int i = 1;i <= tot;++i)
{
f[i][1] = min(f[i-1][0],f[i-1][1])+calc(pos[i],pos[i]+1);
if (pos[i-1]<pos[i]-1) f[i][0] = min(f[i-1][0],f[i-1][1])+calc(pos[i]-1,pos[i]);
else f[i][0] = f[i-1][0]+calc(pos[i]-1,pos[i]);
if (i >= 2&&pos[i] == pos[i-1]+1)
{
if (pos[i-2]<pos[i-1]-1) f[i][0] = min(f[i][0],min(f[i-2][0],f[i-2][1])+calc(pos[i-1],pos[i]));
else f[i][0] = min(f[i][0],f[i-2][0]+calc(pos[i-1],pos[i]));
}
}
} int main()
{
freopen("1237.in","r",stdin);
freopen("1237.out","w",stdout);
scanf("%d",&n); for (int i = 1;i <= n;++i) scanf("%lld %lld",A+i,B+i);
A[0] = A[n+1] = inf; pos[0] = -100;
sort(A+1,A+n+1); sort(B+1,B+n+1);
for (int i = 1;i <= n;++i)
{
sum += abs((A[i]-B[i]));
if (A[i] == B[i]) pos[++tot] = i;
}
dp(); printf("%lld",sum+min(f[tot][0],f[tot][1]));
fclose(stdin); fclose(stdout);
return 0;
}

BZOJ 1237 配对的更多相关文章

  1. BZOJ 1237 配对(DP)

    给出两个长度为n的序列.这两个序列的数字可以连边当且仅当它们不同,权值为它们的绝对值,求出这个二分图的最小权值完全匹配.没有输出-1. n<=1e5.用KM会TLE+MLE. 如果连边没有限制的 ...

  2. bzoj 1237 [SCOI2008]配对 贪心+dp

    思路:dp[ i ] 表示 排序后前 i 个元素匹配的最小值, 我们可以发现每个点和它匹配的点的距离不会超过2,这样就能转移啦. #include<bits/stdc++.h> #defi ...

  3. BZOJ 1786 配对(DP)

    如果我们直接令dp[i][j]为前i个位置第i个位置填j所产生的逆序对的最少数.这样是不满足无后效性的. 但是如果发现对于两个-1,如果前面的-1填的数要大于后面的-1填的数.容易证明把他们两交换结果 ...

  4. dp专练

    dp练习. codevs 1048 石子归并 区间dp #include<cstdio> #include<algorithm> #include<cstring> ...

  5. bzoj千题计划179:bzoj1237: [SCOI2008]配对

    http://www.lydsy.com/JudgeOnline/problem.php?id=1237 如果没有相同的数不能配对的限制 那就是排好序后 Σ abs(ai-bi) 相同的数不能配对 交 ...

  6. BZOJ 4205: 卡牌配对

    4205: 卡牌配对 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 173  Solved: 76[Submit][Status][Discuss] ...

  7. 图论(费用流):BZOJ 4514 [Sdoi2016]数字配对

    4514: [Sdoi2016]数字配对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 820  Solved: 345[Submit][Status ...

  8. BZOJ 4514: [Sdoi2016]数字配对 [费用流 数论]

    4514: [Sdoi2016]数字配对 题意: 有 n 种数字,第 i 种数字是 ai.有 bi 个,权值是 ci. 若两个数字 ai.aj 满足,ai 是 aj 的倍数,且 ai/aj 是一个质数 ...

  9. BZOJ.4514.[SDOI2016]数字配对(费用流SPFA 二分图)

    BZOJ 洛谷 \(Solution\) 很显然的建二分图后跑最大费用流,但有个问题是一个数是只能用一次的,这样二分图两部分都有这个数. 那么就用两倍的.如果\(i\)可以向\(j'\)连边,\(j\ ...

随机推荐

  1. CentOS Nginx+jdk+tomcat 环境搭建

    一.jdk安装 jdk下载地址:http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloa ...

  2. 晕,hibernate 的 merge和cascade="all-delete-orphan"要慎重合在一起使用

    遇到一个比较后悔莫及事情,使用了hibernate 的 merge和cascade="all-delete-orphan" ,子表数据被删除了. 1.使用cascade=" ...

  3. Android开发进阶:如何读写Android文件

    Android主要有四大主要组件组成:Activity.ContentProvider.Service.Intent组成.Android文件的运行主要需要读写四大组件的文件.本文将介绍如何读写Andr ...

  4. Asp.net简单三层+Sqllite 增删改查

    新建项目à新建一个空白解决方案 在Model新建一个实体类 using System; using System.Collections.Generic; using System.Linq; usi ...

  5. html 之前学习响应式的笔记

    响应式的设计,根据用户设备的不同,用户屏幕大小不同,提供不同的网页设计http://mediaqueri.es/PhoneGap 使用2,如何模拟手机设备chome 浏览器 在32以上设备检测用 de ...

  6. HTML 5 全局属性

    下面的全局属性可用于任何 HTML5 元素.HTML 5 全局属性NEW:HTML 5 中新的全局属性.属性 描述accesskey 规定访问元素的键盘快捷键class   规定元素的类名(用于规定样 ...

  7. c#中string.trimstart() 和string.trimend() 的用法

    trim(),trimstart(),trimend()这样写是去掉空格,trimstart(a)是去掉字符串开始包含char[] a的字符,trimend同trimstart. 例:char[] a ...

  8. C# 文件粉碎

    >文件粉碎的流程 填充文件 更改最后使用/创建时间 更改名称 将大小改为 0 kb 删除 using System; using System.Collections.Generic; usin ...

  9. c#中var关键字用法

    Technorati 标签: C# 转载自csdn:http://blog.csdn.net/robingaoxb/article/details/6175533   var关键字是C# 3.0开始新 ...

  10. asp.net - GridView根据linkButton值不同跳转不同页面

    一,当前页面中,前台界面的主要代码: <asp:TemplateField HeaderText="姓名"> <ItemTemplate> <!--根 ...