[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;
}
原文地址:https://www.cnblogs.com/mrclr/p/10483607.html