POJ 1201-Intervals

Description

You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn.
Write a program that:
reads the number of intervals, their end points and integers c1, ..., cn from the standard input,
computes the minimal size of a set Z of integers which has at least ci common elements with interval [ai, bi], for each i=1,2,...,n,
writes the answer to the standard output.

Input

The first line of the input contains an integer n (1 <= n <= 50000) -- the number of intervals. The following n lines describe the intervals. The (i+1)-th line of the input contains three integers ai, bi and ci separated by single spaces and such that 0 <= ai <= bi <= 50000 and 1 <= ci <= bi - ai+1.

题目大意:

给出n个闭区间[ai,bi],每个区间对应一个ci,表示集合Z在区间[ai,bi]内至少有ci个相同元素,问集合Z至少有几个元素。
每个测试点有多组输入数据
每组第一行为n (1 <= n <= 50000)。接下来n行,每行给出一组ai,bi,ci。(0 <= ai <= bi <= 50000,1 <= ci <= bi - ai+1.

Output

The output contains exactly one integer equal to the minimal size of set Z sharing at least ci elements with interval [ai, bi], for each i=1,2,...,n.
要求输出集合Z中最少有几个元素,题目保证有解。

Sample Input

5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1

Sample Output

6

题解

差分约束系统。最近恶补知识面,看清北学堂2013年noip的视频时,想起来要做点题练练了。

首先从视频上对差分约束系统大致的认识是:将题目给出不等式作为最短(长)路的限制条件,跑最短(长)路,当有负环时无解。

可是这道题没给我们不等式,但有“最小”这个条件,所以用Si表示区间[0,i]区间内至少有多少个元素的话,那么Sbi - Sai >= ci。可转换为Sbi>= Sai+ci,这可作为跑最长路的限制条件了。可是这样50000个点只连了少量边,可能跑不出我们想要的最短路。为了保险,还有一个式子:0<=Si - Si-1<=1,这样就能跑最长路了。因为题目保证有解,所以不用判负环。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
#define inf 1<<30
using namespace std;
int n,head[50005],zz,S,T;
struct bian{int to,nx,v;} e[200002];
int dis[50005],pd[50005],q[50005];
void insert(int x,int y,int z)
{
	zz++; e[zz].to=y; e[zz].v=z; e[zz].nx=head[x]; head[x]=zz;
}
void init()
{
	memset(head,0,sizeof(head));
	zz=0; S=inf; T=-inf;
	int i,a,b,c;
	for(i=1;i<=n;i++)
	   {scanf("%d%d%d",&a,&b,&c);
	    insert(a,b+1,c);
		//因为a>=0,为了让a-1不超界,所以将所有点向正方向平移一位 
	    S=min(S,a); T=max(T,b+1);
	   }
	for(i=S;i<T;i++)
	   {insert(i,i+1,0); insert(i+1,i,-1);}
}
void spfa()
{
	int t=0,w=1,i,p;
	for(i=S;i<=T;i++) {dis[i]=-inf; pd[i]=0;}
	dis[S]=0; pd[S]=1; q[t]=S;
	while(t!=w)
	   {p=q[t];
	    t=(t+1)%50003;
	    for(i=head[p];i;i=e[i].nx)
	       {if(dis[e[i].to]<dis[p]+e[i].v)
		      {dis[e[i].to]=dis[p]+e[i].v;
			   if(!pd[e[i].to])
			      {pd[e[i].to]=1; q[w]=e[i].to; w=(w+1)%50003;}
			  }
		   }
		pd[p]=0;
	   } 
	printf("%d\n",dis[T]);
}
int main()
{
	
	while(scanf("%d",&n)!=EOF)
	   {init(); spfa();}
	return 0;
} 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值