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 }

  

原文地址:https://www.cnblogs.com/zub23333/p/8794966.html