Description
一次考试共有n个人参加,第i个人说:“有ai个人分数比我高,bi个人分数比我低。”问最少有几个人没有说真话(可能有相同的分数)
Input
第一行一个整数n,接下来n行每行两个整数,第i+1行的两个整数分别代表ai、bi
Output
一个整数,表示最少有几个人说谎
Sample Input
3
2 0
0 2
2 2
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减去即可。。。
那么一个人说的话可以看做一个带权区间,那么我们就是要求出能选出多少个不相交的区间,使得这些区间的权最大。。。
(因为区间相交表示有更多的人分数相同,显然至少有一个人说了假话。。。)
dp的话枚举右端点,然后把以该点为右端点的线段dp一下,用了Map nlogn
// 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-dp[n]); return 0; }