题目概述
有 n n 个人,第 个人说有 ai a i 人排名在他前面, bi b i 个人排名在他后面(可以有相同排名),问最少有几人说谎。
解题报告
第 i i 个人的排名范围是 , a a 不同或 不同的两个人都说真话时区间不能有冲突(否则两人可能为相同排名,这是不可能的)。所以我们可以DP,定义 f[i] f [ i ] 表示前 i i 名最多有多少人说真话,那么每个 都是一条 a−1→b a − 1 → b 的转移。最后 n−f[n] n − f [ n ] 就是答案。
注意同一区间 [x,y] [ x , y ] 中如果人数超过 y−x+1 y − x + 1 那么贡献只有 y−x+1 y − x + 1 。
示例程序
#include<cstdio>
#include<algorithm>
#define fr first
#define sc second
using namespace std;
const int maxn=100000;
int n,f[maxn+5];pair<int,int> a[maxn+5];
int E,lnk[maxn+5],nxt[maxn+5],son[maxn+5],w[maxn+5];
#define Add(x,y,z) son[++E]=(y),w[E]=(z),nxt[E]=lnk[x],lnk[x]=E
int main(){
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
for (int i=(scanf("%d",&n),1);i<=n;i++) scanf("%d%d",&a[i].fr,&a[i].sc);
sort(a+1,a+1+n);
for (int i=1,j;i<=n;i=j){
for (j=i;j<=n&&a[i]==a[j];j++);
int x=a[i].fr+1,y=n-a[i].sc;if (x>y) continue;
Add(y,x-1,min(y-x+1,j-i));
}
for (int i=1;i<=n;f[i]=max(f[i],f[i-1]),i++)
for (int j=lnk[i];j;j=nxt[j])
f[i]=max(f[i],f[son[j]]+w[j]);
return printf("%d\n",n-f[n]),0;
}