洛谷传送门
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 1≤n≤100000, 0 ≤ a i 、 b i ≤ n 0≤ai、bi≤n 0≤ai、bi≤n
解题分析
从每个人的描述可以知道他属于一个区间 [ 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]);
}