[Luogu P2519] [BZOJ 2298] [HAOI2011]problem a

洛谷传送门
BZOJ传送门

题目描述

一次考试共有 n n n个人参加,第 i i i个人说:“有 a i a_i ai个人分数比我高, b i b_i bi个人分数比我低。”问最少有几个人没有说真话(可能有相同的分数)

输入输出格式

输入格式:

第一行一个整数 n n n,接下来 n n n行每行两个整数,第 i + 1 i+1 i+1行的两个整数分别代表 a i a_i ai b i b_i bi

输出格式:

一个整数,表示最少有几个人说谎

输入输出样例

输入样例#1:
3
2 0
0 2
2 2
输出样例#1:
1

说明

100%的数据满足: 1 ≤ n ≤ 100000 1≤n≤100000 1n100000 0 ≤ a i 、 b i ≤ n 0≤ai、bi≤n 0aibin

解题分析

从每个人的描述可以知道他属于一个区间 [ l i , r i ] [l_i,r_i] [li,ri], 并且这个区间内的人都有同样的分数。 那么事实上我们就是求本质不同的不相交区间的个数最大是多少。(相同的我们合并起来, 贡献加1)。直接对右端点排序, 线段树维护 d p dp dp转移即可。

但这道题有个很坑的地方: 相同的区间个数可能超过区间长度, 显然这些人也在说假话, 这时候我们就要取一个 m i n min min

代码如下:

#include <cstdio>
#include <cstring>
#include <cstring>
#include <cctype>
#include <cmath>
#include <map>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 100500
template <class T>
IN void in(T &x)
{
	x = 0; R char c = gc;
	for (; !isdigit(c); c = gc);
	for (;  isdigit(c); c = gc)
	x = (x << 1) + (x << 3) + c - 48;
}
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
struct INFO {int lef, rig;};
IN bool operator < (const INFO &x, const INFO &y)
{return x.rig == y.rig ? x.lef < y.lef : x.rig < y.rig;}
std::map <INFO, int> mp;
std::map <INFO, int>::iterator it;
int num, ans;
int dp[MX], mx[MX << 2];
namespace SGT
{
	#define ls (now << 1)
	#define rs (now << 1 | 1)
	IN void pushup(R int now) {mx[now] = max(mx[ls], mx[rs]);}
	void modify(R int now, R int lef, R int rig, R int tar, R int val)
	{
		if (lef == rig) return mx[now] = max(mx[now], val), void();
		int mid = lef + rig >> 1;
		if (tar <= mid) modify(ls, lef, mid, tar, val);
		else modify(rs, mid + 1, rig, tar, val);
		pushup(now);
	}
	int query(R int now, R int lef, R int rig, R int rb)
	{
		if (rig <= rb) return mx[now];
		int mid = lef + rig >> 1, ret = query(ls, lef, mid, rb);
		if(rb > mid) ret = max(ret, query(rs, mid + 1, rig, rb));
		return ret;
	}
	#undef ls
	#undef rs
}
int main(void)
{
	int a, b;
	in(num);
	for (R int i = 1; i <= num; ++i)
	{
		in(a), in(b);
		if (a + b >= num) continue;//多于人数, 显然是假话
		++mp[{a + 1, num - b}];
	}
	for (it = mp.begin(); it != mp.end(); it++)
	{
		it -> second = min((it -> first).rig - (it -> first).lef + 1, it -> second);
		dp[(it -> first).rig] = max(dp[(it -> first).rig], SGT::query(1, 0, num, (it -> first).lef - 1) + (it -> second));
		SGT::modify(1, 0, num, (it -> first).rig, dp[(it -> first).rig]);
	}
	printf("%d", num - mx[1]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值