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. java中使用队列:java.util.Queue

    在java5中新添加了java.util.Queue接口,用以支持队列的常见操作.该接口扩展了java.util.Collection接口.Queue使用时要尽量避免Collection的add()和 ...

  2. vim的全局替换

    本文出自   http://blog.csdn.net/shuangde800 本文是在学习<使用vi编辑器, Lamb & Robbins编著>时在所记的笔记. 本文内容: 基本 ...

  3. LabVIEW设计模式系列——case结构模拟事件结构

    标准:1.所有按钮的机械动作必须都用释放时触发或者单击时触发,这是为了保证仅仅触发一次动作. 标准:1.使用简单的case结构模拟事件结构.

  4. linux 上不去网

    linux 上不去网   ip dns无误 ping可以到达网关 可能原因 网卡睡眠 ethtool eht0  //查看eht0网口基本设置 mii-tool -w eth0

  5. Nunit概要

    一.NUnit是一个单元测试框架,专门针对于.NET来写的.其实在前面有JUnit(Java),CPPUnit(C++),他们都是xUnit的一员.最初,它是从JUnit而来.现在的版本是2.2.接下 ...

  6. Java SE (1)之 JFrame 组件 FlowLayout 布局

    package com.sunzhiyan; import java.awt.*; import java.awt.event.*; import javax.swing.*; public clas ...

  7. Asp.Net Remove Unwanted Headers

    原文:http://blogs.msdn.com/b/varunm/archive/2013/04/23/remove-unwanted-http-response-headers.aspx 原文:h ...

  8. 关于wordpress中更换CKEditor编辑器

    wordpress中自带的编辑器实在是功能太简,连插入表格都没有,使用插件的方式太过于麻烦,干脆就直接更换编辑器了,在网上找了一些方法,下文引自http://down.chinaz.com/try/2 ...

  9. 编写适合windows 7 平台的软件,给程序添加UAC认证

    Delphi程序必须在资源里面嵌入MANIFEST信息 一. 首先编辑一个文件,内容如下: <?xml version="1.0" encoding="UTF-8& ...

  10. Excel数据导入到oracle

    打开pl/sql,如图所示界面,点击菜单栏中的T00LS     ODBC Imtorper,打开ODBC Importer选项框       在Data fromODBC页中选择需要导入的文件的格式 ...