关闭

BZOJ3414: Poi2013 Inspector

标签: BZOJpoi二分贪心构造
613人阅读 评论(0) 收藏 举报
分类:

题目大意:一天公司有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 707185547
using 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();
}


 

 

 

0
0
查看评论

POI读取Excel2013

import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import org.apache.poi.ss.usermodel.Cell; import org.apache.po...
  • w12ert
  • w12ert
  • 2015-11-03 10:45
  • 789

POI2013 题解

明显感觉POI2013比14和15难很多.....不看题解只做上了四道...... 而且POI2013感觉网上题解不是很多啊,大部分还是得看波兰文题解,所以最后也没做上几道题,很悲剧啊 题解链接: Stage I:  Price List    ...
  • commonc
  • commonc
  • 2016-06-14 15:16
  • 657

BZOJ3417 Poi2013 Tales of seafaring

我们可以在两个点之间来回反复,所以问题就变成了判断两点之间道路条数为奇数或偶数的最短路是否小于等于d 分成图,边都跨层连,即可算出奇数最短路和偶数最短路 注意特判孤立点询问自己的情况 #include #include #include #include #include #include #...
  • neither_nor
  • neither_nor
  • 2016-09-22 14:19
  • 437

BZOJ3417: Poi2013 Tales of seafaring

题目大意:给n个点m条边无向图,每次询问两个点之间是否有长度为d的路径(不一定是简单路径)   从a到b假如有长度为x的路径,那就可以往回走一步再往前走一步得到长度为x+2的路径 所以可以求出每对点之间的奇数长度最短路和偶数长度最短路,然后判断是否小于d即可 PS: 1.这题卡内...
  • commonc
  • commonc
  • 2016-05-31 14:46
  • 472

bzoj 3417: Poi2013 Tales of seafaring bfs

题意一个n点m边无向图,边权均为1,有k个询问,每次询问给出(s,t,d),要求回答是否存在一条从s到t的路径,长度为d,路径不必是简单路(可以自交)。 n,m<=5000,k<=1000000,d<=1000000000分析考虑到若从s可以走d步到达t,则s必然可以走t+2步到...
  • qq_33229466
  • qq_33229466
  • 2016-12-14 19:30
  • 348

3427: Poi2013 Bytecomputer

3427: Poi2013 Bytecomputer Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 202  Solved: 116 [Submit][Statu...
  • CRZbulabula
  • CRZbulabula
  • 2017-01-18 15:37
  • 130

POI2013

bzoj 3144先二分答案,然后就是求一些条件是否都可行。 首先一个人一定在第一次记录到最后一次记录的这段区间内出现。 然后每段区间可以两边扩展,如果一个人没有记录过那么他的区间是任意的。 那么可以把当前工作的人分成三类:在区间内的人,区间未开始的人,区间已经结束的人。 没记录过的人属于第...
  • make_it_for_good
  • make_it_for_good
  • 2016-09-28 17:23
  • 243

[POI 2013]Bytecomputer(DP)

题目链接http://main.edu.pl/en/archive/oi/20/baj题目大意给你一个长度为nn的序列aa,序列里每个元素要么是0,要么是-1,要么是1,每次操作可以让a[x]=a[x]+a[x−1]a[x]=a[x]+a[x-1],问至少要做多少次操作,才能让整个序列变成非降序列思...
  • qpswwww
  • qpswwww
  • 2015-05-14 15:11
  • 666

BZOJ3427 Poi2013 Bytecomputer

发现答案肯定是前边一段-1,中间一段0,后边一段1的形式(可能有的段长度为0),可以证明出现2或者-2或者绝对值更大的数一定不是最优解 做一个f[i]和g[i],f[i]表示把i到n都变成1的代价,g[i]表示把1到i都变成-1的代价 那么如果第一个数就是1,那么肯定要把所有数都变成1,如果第一...
  • neither_nor
  • neither_nor
  • 2016-09-22 16:15
  • 344

洛谷3558[POI2013]BAJ-Bytecomputer

[POI2013]BAJBytecomputer
  • LittleLittleMo
  • LittleLittleMo
  • 2017-06-04 17:37
  • 209
    个人资料
    • 访问:100190次
    • 积分:2507
    • 等级:
    • 排名:第17323名
    • 原创:156篇
    • 转载:3篇
    • 译文:0篇
    • 评论:27条