• problem a [HAOI2011]


                                   题目传送门

    题目描述:

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

    输入格式:

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

    输出格式:

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

    样例输入:

    3

    2 0

    0 2

    2 2

    样例输出:

    1

    数据范围:

    30%的数据满足:1≤n≤1000

    100%的数据满足:1≤n≤1000000≤ai、bi≤n

     题解:

      首先算出每个人的排名所能够位于的区间[l,r],即l=a+1,r=n-b。明显当l>r时是没有意义的,且该区间内的所有学生要同分。

      再考虑如果两个人的区间无交集,那显然是互不影响的。如果两个人的区间有交集,比如学生a的排名区间为[1,2],b的排名区间为[2,3],假设两个人都说的是真话,那么根据上面的结论可得a的分数与b的分数一样。而比a分数高的人的数量为0,比b分数高的人的数量为1,这显然是不可能的。

      如果两个人的排名区间一样,只要区间内位置足够,两个人就是不矛盾的。所以我们可以将排名相同的人的区间合并,权值相加。

      最后问题就转化成了有m个区间,每个区间有一个权值,让你求最大互不相交区间权值和。可以用动态规划求解。

      一个很容易想到的状态为f[i]表示将区间按右端点从小到大排序后前i个区间所能够得到的最大权值和,转移方程为:f[i] = max{f[j]+v[i]} ( j<i , r[j] < l[i] )。

      但是n^2显然是超时的。

      我们可以注意到f[i]是单调递增的,所以我们可以二分答案把复杂度降到n*logn。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define LL long long
     6 #define RI register int
     7 using namespace std;
     8 const int INF = 0x7ffffff ;
     9 const int N = 1000000 + 10 ;
    10 
    11 inline int read() {
    12     int k = 0 , f = 1 ; char c = getchar() ;
    13     for( ; !isdigit(c) ; c = getchar())
    14       if(c == '-') f = -1 ;
    15     for( ; isdigit(c) ; c = getchar())
    16       k = k*10 + c-'0' ;
    17     return k*f ;
    18 }
    19 struct data {
    20     int l, r, val ;
    21 }p[N], lin[N] ;
    22 int n ; int f[N], mm[N] ;
    23 
    24 inline bool cmp1(data s,data t) { return s.l == t.l ? s.r < t.r : s.l < t.l ; }
    25 inline bool cmp2(data s,data t) { return s.r == t.r ? s.l < t.l : s.r < t.r ; }
    26 int main() {
    27 //    freopen("a.in","r",stdin) ;
    28 //    freopen("a.out","w",stdout) ;
    29     n = read() ; int tot = 0 ;
    30     for(int i=1;i<=n;i++) {
    31         int x = read(), y = read() ; if(x+y >= n) continue ;
    32         p[++tot].l = x+1, p[tot].r = n-y ;
    33     }
    34     sort(p+1,p+tot+1,cmp1) ;
    35     int tt = 0 ;
    36     for(int i=1;i<=tot;) {
    37         lin[++tt].l = p[i].l, lin[tt].r = p[i].r, lin[tt].val = 1 ; int j ;
    38         for(j=i+1;p[i].l == p[j].l && p[i].r == p[j].r;j++) lin[tt].val ++ ;
    39         if(lin[tt].val > (lin[tt].r-lin[tt].l+1)) lin[tt].val = lin[tt].r-lin[tt].l+1 ;
    40         i = j ;
    41     }
    42     sort(lin+1,lin+tt+1,cmp2) ;
    43     for(int i=1;i<=tt;i++) {
    44         int L = 1, R = i-1, k = 0 ;
    45         while(L <= R) {
    46             int mid = (L+R)>>1 ;
    47             if(lin[mid].r < lin[i].l) k = max(k,mid), L = mid+1 ;
    48             else R = mid-1 ;
    49         }
    50         f[i] = max(f[i-1],f[k]+lin[i].val) ;
    51     }
    52     printf("%d",n-f[tt]) ;
    53     return 0 ;
    54 }

      

  • 相关阅读:
    人间故事馆话题:聊聊那些被骗经历,让其他人不再被骗
    路过的风景
    路过的风景
    上海最适合拍照的旅游地点
    Java EE (11)
    五、服务器端的局域网
    P1294 高手去散步 洛谷
    堆排序【模板】
    P3383 【模板】线性筛素数 洛谷
    P1516 青蛙的约会 洛谷
  • 原文地址:https://www.cnblogs.com/zub23333/p/8794966.html
Copyright © 2020-2023  润新知