首页 > 代码库 > bzoj 2298: [HAOI2011]problem a

bzoj 2298: [HAOI2011]problem a

Description

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

Input

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

Output

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

Sample Input

3

2 0

0 2

2 2

Sample Output

1

HINT

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

Source

首先我们需要对问题进行一下转化。。。

一个人有a个人比他分高,b个人比他分低。

如果他说的是对的,那么排名[a+1,n-b]的人的分数是相同的,且这些人与其他人的分数都不同。。。

题目问说谎的人最少有多少,那么变为说真话的最多有多少,然后用n减去即可。。。

那么一个人说的话可以看做一个带权区间,那么我们就是要求出能选出多少个不相交的区间,使得这些区间的权最大。。。

(因为区间相交表示有更多的人分数相同,显然至少有一个人说了假话。。。)

然后n^2 dp就可以了(没有看到数据范围,讲道理要加个树状数组的。。。)

// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const int N=100050;
map<pair<int,int>,int> Map;
vector<int> p[N];
int dp[N],n;
int main(){
  scanf("%d",&n);
  for(int i=1;i<=n;i++){
    int a,b;scanf("%d%d",&a,&b);
    int l=a+1,r=n-b;
    if(l>r) continue;
    Map[make_pair(l,r)]++;
    if(Map[make_pair(l,r)]==1) p[r].push_back(l);
  }
  for(int i=1;i<=n;i++){
    dp[i]=dp[i-1];
    for(int j=0;j<p[i].size();j++){
      int k=p[i][j];
      dp[i]=max(dp[i],dp[k-1]+min(Map[make_pair(k,i)],i-k+1));
    }
  }
  printf("%d\n",n-dp[n]);
  return 0;
}

  

bzoj 2298: [HAOI2011]problem a