zoukankan      html  css  js  c++  java
  • [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;
    }
    
  • 相关阅读:
    营山护照办理
    非北京人员 办理护照
    护照填写注意事项
    美国会议签证——我是正当理由去美国,我能支付(或有人为我支付)我在美国期间的所有费用,办完事我肯定回来, 邀请信,行程表这些材料齐全即可
    urllib2使用2
    python 异常
    python urllib和urllib2 区别
    python类继承
    gcc编译4个阶段
    Vim中如何全选并复制?
  • 原文地址:https://www.cnblogs.com/mrclr/p/10483607.html
Copyright © 2011-2022 走看看