BZOJ3414: Poi2013 Inspector
来源:互联网 发布:c语言在线编译 输入 编辑:程序博客网 时间:2024/04/19 06:18
题目大意:一天公司有n个员工和m个员工记录,每个员工只会在连续的一段时间内工作。现在给出m条记录分别是谁写的、什么时候写的以及写的时候除了他还有多少人。求最大的k使得前k条记录互不矛盾
挺神的题...
首先二分答案转成判定性问题,这样记录就没有先后顺序之分了
然后考虑什么情况会出现矛盾:
1.记录本身的矛盾:两条记录是同一时刻,但人数不同
判断方法:这个是很显然的了,可以直接特判
2.记录的记载人产生的约束关系而形成的矛盾:
比如说一个人在a时刻写过记录,又在b时刻写过记录,这就说明a到b的时刻他都在公司,这时假如中间有个人写除了他以外没人了,那肯定就不对了
判断方法:我们可以对每个人记录一下最晚开始时间和最早结束时间,当成一条线段,对于每个时间节点,看他被几条线段覆盖,如果线段条数大于当前时间记录的人数,就说明一定无解
3.根据记录可以构造出一种方案,但是会超过n个人的限制:
这个跟上一条的不同点在于,他是可以根据约束条件构造出方案的
比如1时刻1记录有两个人,2时刻1记录有1个人,3时刻1记录有两个人,显然n=3时是可以的,但n=2就不行
所以我们只需要算出他的最小符合条件的人数,判断一下是否小于等于n就可以了,那么怎么算呢?
首先我们按照时间顺序来扫,还是像2一样每个人对应一段区间
除了当前必须人数(2中的线段条数)now和当前最小符合条件的人数total以外,我们开两个变量来辅助计算
done表示所对应区间已经过去了,还留下来可以继续工作的人数
notbegin表示所对应区间还没到,但是提前开始工作的人数
每到一个新的时刻,我们可以比较一下now+done+notbegin与tot[i](这个点记录的人数)的大小
如果比tot[i]小,说明人数还不够,则我们需要再让一些人提前开始工作
如果比tot[i]大,那说明人数多了,我们就优先让对应区间已经过去了的人结束工作,如果还是多,那就让notbegin的人结束工作
这时可能会有一个问题,notbegin的区间还没到怎么可以结束工作呢,这样不是相当于无解了吗?
我一开始也是这么想的,于是直接return false交了一发,WA了
原因就是,并不是所有的人都有一个确定的对应区间,有很多人都是没写记录的,那么这些人就可以随时开始随时结束,这里notbegin减下去的是这些人
具体可以看看代码
#include<iostream>#include<cstdio>#include<algorithm>#define N 100010#define xrf 707185547using namespace std;int n,m;int t[N],u[N],v[N];int mn[N],mx[N];int tot[N];int st[N],en[N];bool check(int M){int i,j;for(i=1;i<=n;i++){mn[i]=xrf;mx[i]=-xrf;}for(i=1;i<=m;i++)tot[i]=st[i]=en[i]=0;for(i=1;i<=M;i++){mn[u[i]]=min(mn[u[i]],t[i]);mx[u[i]]=max(mx[u[i]],t[i]);if(tot[t[i]]&&tot[t[i]]!=v[i]+1) return false;tot[t[i]]=v[i]+1;}for(i=1;i<=n;i++)if(mx[i]!=-xrf){st[mn[i]]++;en[mx[i]]++;}int total=0,now=0;int done=0,notbegin=0;for(i=1;i<=m;i++)if(tot[i]){now+=st[i];if(now>tot[i]) return false;if(st[i]<=notbegin) notbegin-=st[i];else total+=st[i]-notbegin,notbegin=0;if(now+notbegin+done<tot[i]) total+=tot[i]-now-notbegin-done,notbegin=tot[i]-now-done;else{if(now+notbegin>tot[i]) /*return false;*/notbegin=tot[i]-now,done=0;else done=tot[i]-now-notbegin;}now-=en[i];done+=en[i];}if(total>n) return false;return true;}void doit(){scanf("%d%d",&n,&m);int i,j;for(i=1;i<=m;i++)scanf("%d%d%d",&t[i],&u[i],&v[i]);int l=1,r=m+1,mid;while(l<r){mid=(l+r)>>1;if(check(mid)) l=mid+1;else r=mid;}printf("%d\n",l-1);}int main(){int T;scanf("%d",&T);while(T--)doit();}
- BZOJ3414: Poi2013 Inspector
- POI2013
- POI2013 题解
- BZOJ3427: Poi2013 Bytecomputer
- BZOJ3420: Poi2013 Triumphal arch
- BZOJ3419: Poi2013 Taxis
- BZOJ3424: Poi2013 Multidrink
- BZOJ3416: Poi2013 Take-out
- BZOJ3415: Poi2013 Price List
- BZOJ3421: Poi2013 Walk
- BZOJ3427 Poi2013 Bytecomputer
- BZOJ3416 Poi2013 Take-out
- BZOJ3425 Poi2013 Polarization
- 3415: Poi2013 Price List
- 3427: Poi2013 Bytecomputer
- BZOJ3421: Poi2013 Walk
- code inspector
- unity Inspector
- javaweb jsp制作留言板
- Android 网络之 Volley+OkHttp+Https
- pat PAT (Advanced Level) Practise 1007. Maximum Subsequence Sum (25)
- 成长历程—基础评教系统维护
- AsyncTask异步任务类的使用
- BZOJ3414: Poi2013 Inspector
- 第十三周,形状类族中的纯虚函数
- CentOS 在线安装mysql5.7
- XML Schema/XSD
- Windows中cmd操作mysql
- 靠谱iOS开发满足的条件--下
- ajax 点赞收藏功能
- 基于MeanShift的目标跟踪算法及实现
- Hdu 1501 Zipper【dfs】