[HAOI2011]problem a
嘟嘟嘟
这题就比较有意思了,十分锻炼思维。
首先得学会转化,对于题中“有\(a_i\)个人比我高,\(b_i\)个人比我低”,相当于排在第\(a_i + 1\)到\(n - b_i\)位的人和我分数相同。
因此我们就把每一个人说的话变成了一段区间,那么说真话的人肯定是所有不相交的区间。乍一看就变成了区间覆盖,水贪心。
结果交上去WA的很惨。
因为这又和线段覆盖不太一样:对于两个完全重合的区间\([L, R]\),这两个区间是都可以选的,表示这两位分数相同。因此如果有一些相同的区间,我们最多可以选\(R - L + 1\)个。
所以我们要对上述区间进行去重,并给新的区间一个值\(val\),表示和他重复的区间有多少个。
那么现在就不能贪心了,变成了简单的dp。
先按\(R\)排序,令\(dp[i]\)表示到第\(i\)个区间的答案。因为区间不能相交,所以\(dp[i] = max \{dp[i - 1], dp[pos] + val[i] \}\),其中\(pos\)满足\(R[pos] < L[i]\)且\(R[pos]\)最大。
二分\(pos\),复杂度就是\(O(nlogn)\)。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 1e5 + 5;
inline ll read()
{
ll ans = 0;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) last = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
}
int n, cnt1 = 0, cnt2 = 0;
struct Node
{
int L, R, val;
}t[maxn], q[maxn];
In bool cmp1(Node a, Node b)
{
return a.L == b.L ? a.R < b.R : a.L < b.L;
}
In bool cmp2(Node a, Node b)
{
return a.R == b.R ? a.L < b.L : a.R < b.R;
}
int dp[maxn];
In int find(int pos)
{
int L = 0, R = pos - 1;
while(L < R)
{
int mid = (L + R + 1) >> 1;
if(q[mid].R < q[pos].L) L = mid;
else R = mid - 1;
}
return L;
}
int main()
{
n = read();
for(int i = 1; i <= n; ++i)
{
int a = read(), b = read();
if(a + b < n) t[++cnt1] = (Node){a + 1, n - b, 1};
}
sort(t + 1, t + cnt1 + 1, cmp1);
for(int i = 1; i <= cnt1; ++i)
if(i == 1 || t[i].L != q[cnt2].L || t[i].R != q[cnt2].R) q[++cnt2] = t[i];
else if(q[cnt2].val < q[cnt2].R - q[cnt2].L + 1) ++q[cnt2].val;
sort(q + 1, q + cnt2 + 1, cmp2);
for(int i = 1; i <= cnt2; ++i)
dp[i] = max(dp[i - 1], dp[find(i)] + q[i].val);
write(n - dp[cnt2]), enter;
return 0;
}