正题
题目链接:https://www.luogu.com.cn/problem/P6117
题目大意
平面上有2n2n2n的硬币,要给每个硬币匹配一个x∈[1,n],y∈[1,2]x\in[1,n],y\in[1,2]x∈[1,n],y∈[1,2]的位置(不能重复)。
使得所有硬币和它们匹配位置的曼哈顿距离之和最小。
1≤n≤105,−109≤Xi,Yi≤1091\leq n\leq 10^5,-10^9\leq X_i,Y_i\leq 10^91≤n≤105,−109≤Xi,Yi≤109
解题思路
先把每个硬币先移进x∈[1,n],y∈[1,2]x\in[1,n],y\in[1,2]x∈[1,n],y∈[1,2]这个范围内,然后考虑贪心去把每个硬币匹配。
我们在同一个xxx的硬币如果上下直接能够补充缺口那么肯定优先上下补充。
不然就从左到右考虑,那么最左边的肯定往右移动多余/请求空缺,记fi,jf_{i,j}fi,j表示位置(i,j)(i,j)(i,j)现在的需求情况即可。
时间复杂度:O(n)O(n)O(n)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1e5+10;
ll n,g[N][2],ans;
signed main()
{scanf("%lld",&n);for(ll i=1,x,y;i<=2*n;i++){scanf("%lld%lld",&x,&y);if(y>=2)ans+=y-2,y=2;else ans+=1-y,y=1;if(x>n)ans+=x-n,x=n;else if(x<1)ans+=1-x,x=1;g[x][y-1]++;}for(ll i=1;i<=n;i++){g[i][0]--;g[i][1]--;if(g[i][0]*g[i][1]<0){if(g[i][0]<0){ll p=min(-g[i][0],g[i][1]);g[i][0]+=p;g[i][1]-=p;ans+=p;}else{ll p=min(g[i][0],-g[i][1]);g[i][0]-=p;g[i][1]+=p;ans+=p;}}ans+=abs(g[i][0])+abs(g[i][1]);g[i+1][0]+=g[i][0];g[i+1][1]+=g[i][1];}printf("%lld\n",ans);return 0;
}