居民迁移
时间限制:3000ms
单点时限:1000ms
内存限制:256MB
描述
公元2411年,人类开始在地球以外的行星建立居住点。在第1326号殖民星上,N个居住点分布在一条直线上。为了方便描述,我们设第i个居住点的位置是Xi,其中居住着Yi位居民。随着冬季的到来,一些人口较多的居住点的生态循环系统已经开始超负荷运转。为了顺利度过严冬,殖民星上的居民一致同意通过转移到人口较少的居住点来减轻人口众多的居住点的负荷。
遗憾的是,1326殖民星的环境非常恶劣。在冬季到来前,每个居民点的居民最远能迁移到距离不超过R的居民点。1326殖民星的居民希望知道,如何安排迁移才能使完成迁移后人口最多的居民点人口最少?
注意有可能存在多个居民点位置相同。
输入
第一行包含一个整数T(1 <= T <= 10),代表测试数据的组数。
每组数据的第一行包含2个整数N(1 <= N <= 100000)和R(0 <= R <= 10^9)。
以下N行每行包含两个整数,Xi和Yi(0 <= Xi, Yi, <= 10^9)。
输出
对于每组数据输出迁移后人口最多的居民点人口最少可能的数目。
- 样例输入
-
3 5 1 10 80 20 20 30 100 40 30 50 10 5 10 10 80 20 20 30 100 40 30 50 10 5 20 10 80 50 10 20 20 30 100 40 30
- 样例输出
-
100 50 48
仨个铺垫:
如果没有距离不超过R的限制,直接总和除个数即可。
如果知道上界,像“纸牌移动”一样贪心就行。
求最大值最小化,二分既可。
正题:
初步思路:难度是预处理每个点的范围,然后最大流来判断是否满流?
再步思路:由于范围肯定是连续处理得到最优,所以用双指针。
自己YY的双指针代码,丑是情有可原的,不过1A了,丑不丑无所谓lia。
不懂双指针的可以去看hihocoder1607辣。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<cmath> #include<algorithm> using namespace std; const int maxn=100010; int a[maxn],b[maxn]; int L,R,r,n; struct in { int x; int y; }s[maxn]; bool cmp(in a,in b){ return a.x<b.x; } bool check(int u) { int p=1,m=1;//p是待装,m是容器指针 for(int i=1;i<=n;i++){ a[i]=s[i].y;b[i]=0;//a是待装,b是容器 } while(p<=n&&m<=n){ while(p<=n&&s[m].x-s[p].x>r) { if(a[p]>0) return false; p++; } while(m<=n&&p<=n){ if(s[p].x-s[m].x>r||b[m]==u) { m++;break; } int tmp=min(a[p],u-b[m]); a[p]-=tmp; b[m]+=tmp; if(a[p]==0) p++; } } for(int i=1;i<=n;i++) if(a[i]>0) return false; return true; } int main() { int i,j,T; scanf("%d",&T); while(T--){ L=R=1; scanf("%d%d",&n,&r); for(i=1;i<=n;i++){ scanf("%d%d",&s[i].x,&s[i].y); R=max(R,s[i].y); } sort(s+1,s+n+1,cmp); while(L<R){ int mid=(L+R)/2; if(check(mid)) R=mid; else L=mid+1; } printf("%d ",L); } return 0; }