【2019/02/18测试T1】梦境

【题目】

传送门

题目描述:

智者奥尔曼曾说过:有缘的人即使相隔海角天涯,也会在梦境中相遇。

IcePrince_1968IcePrincess_1968 便是如此。有一天 IcePrincess_1968 突发奇想:为什么不用梦境操控仪器来增加她和 IcePrince_1968 的缘分呢?

IcePrincess_1968 的梦境可以用 n n 个区间来表示,第 i i 个区间 [    l i    ,    r i    ] [\;l_i\;,\;r_i\;] 表示她的第 i i 个梦境会在 l i l_i 时刻开始,在 r i r_i 时刻结束(包含 l i l_i r i r_i 两个时刻)。因为 IcePrincess_1968 经常做白日梦,所以 n n 可能很大。

两个人的梦境不是什么时候都能融合的。只有在一些关键的与另一个人相关的梦境转折点两个人的梦境相遇,才能完成融合,形成浪漫的梦境。IcePrincess_1968 探测到 IcePrince_1968 近期的 m m 个与 IcePrincess_1968 相关的梦境转折点,第 i i 个转折点 t i t_i 表示他的第 i i 个梦境转折点会在 t i t_i 时刻出现。因为 IcePrince_1968IcePrincess_1968 很有缘,IcePrince_1968 经常梦到 IcePrincess_1968,所以 m m 可能会很大。

IcePrincess_1968 的一个梦境包含了 IcePrince_1968 的一个梦境转折点时,两个人的这两段梦境就能得到融合。但要注意 IcePrincess_1968 的每段梦境只能和 IcePrince_1968 的一个梦境转折点融合,类似的,IcePrince_1968 的每个梦境转折点只能和 IcePrincess_1968 的一段梦境融合,否则会引发时空混乱。

IcePrincess_1968 很喜欢做和 IcePrince_1968 相关的梦。所以她想算出她的这些梦境最多能和 IcePrince_1968 的梦境转折点融合出多少个浪漫的梦境。但是 IcePrincess_1968 擅长文学但不擅长计算机,所以只能找你帮忙。

输入格式:

文件的第一行为有两个正整数 n , m n,m ,表示 IcePrincess_1968 的梦境个数和 IcePrince_1968 的与 IcePrincess_1968 相关的梦境转折点个数。

​ 第 2 2 至第 n + 1 n+1 行,每行两个正整数 l i , r i l_i,r_i ,第 i + 1 i+1 行的两个数刻画了 IcePrincess_1968 的第 i i 段梦境,含义如题面中所述。

扫描二维码关注公众号,回复: 5397095 查看本文章

​ 第 n + 2 n+2 至第 n + m + 1 n+m+1 行,每行一个正数 t i t_i ,第 i n 1 i-n-1 行的两个数刻画了 IcePrince_1968 的第 i n 1 i-n-1 个梦境转折点,含义如题面中所述。

输出格式:

输出文件仅一行,一个非负整数表示 IcePrincess_1968 最多能获得多少段浪漫的梦境。

样例数据:

输入
2 2
1 3
2 4
1
3

输出
2

提示:

【输入输出样例 1 解释】

​IcePrincess_1968 可以将自己的第一段梦境和第一个梦境转折点匹配,第二段梦境和第二个梦境转折点匹配,从而获得两段浪漫的梦境。因为 IcePrincess_1968 一共只做了两个梦,所以这一定是最多的数量。

【数据范围】

对于 30 % 30\% 的数据, n 10 n\le10 m 10 m\le10

对于 50 % 50\% 的数据, n 100 n\le100 m 100 m\le100

对于 70 % 70\% 的数据, n 2000 n\le2000 m 2000 m\le2000

对于 100 % 100\% 的数据, n 2 × 1 0 5 n\le2\times 10^5 m 2 × 1 0 5 m\le2\times 10^5 1 l i r i 1 0 9 1\le l_i\le r_i\le 10^9 1 t i 1 0 9 1\le t_i\le10^9


【分析】

这是一道贪心啊,考试的时候打了 70 70 分网络流暴力就没管了。。。

我们将梦境转折点从小到大排序,依次为每个梦境转折点安排梦境。

对于一个梦境转折点,最优的选法就是选包含它的区间中右端点离它最近的区间。如果没有区间包含它或包含它的区间已被选,跳过这个店就可以了。

正确性比较显然,这里不给出证明,可以自己画图理解一下。

然后可以用离散化 + + 优先队列来优化这一过程,就可以通过这道题啦。

时间复杂度 O ( n log 2 n ) O(n\log_2n)


【代码】

#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 800005
#define inf ((1ll<<31)-1)
using namespace std;
int n,m,k,sum=0,Max=0;
int l[N],r[N],t[N],d[N],S[N];
vector<int>right[N];
priority_queue<int>q;
void discrete()
{
	sort(d+1,d+sum+1);
	k=unique(d+1,d+sum+1)-(d+1);
	for(int i=1;i<=n;++i)
	{
		l[i]=lower_bound(d+1,d+k+1,l[i])-d;
		r[i]=lower_bound(d+1,d+k+1,r[i])-d;
		right[l[i]].push_back(r[i]),Max=max(Max,r[i]);
	}
	for(int i=1;i<=m;++i)
	  t[i]=lower_bound(d+1,d+k+1,t[i])-d,S[t[i]]++,Max=max(Max,t[i]);
}
int main()
{
	int x,i,j,ans=0;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;++i)
	{
		scanf("%d%d",&l[i],&r[i]);
		d[++sum]=l[i],d[++sum]=r[i];
	}
	for(i=1;i<=m;++i)
	  scanf("%d",&t[i]),d[++sum]=t[i];
	discrete();
	for(i=1;i<=Max;++i)
	{
		for(j=right[i].size()-1;j>=0;--j)  q.push(-right[i][j]);
		while(S[i]--)
		{
			while(!q.empty()&&(-q.top())<i)  q.pop();
			if(!q.empty())  ans++,q.pop();
		}
	}
	printf("%d",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/87616526
t1