bzoj2298: [HAOI2011]problem a(dp)
2298: [HAOI2011]problem a
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1472 Solved: 723
[Submit][Status][Discuss]
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
/*
对于每一个描述,我们可以根据他所描述的比他高的和比他矮的人数来构造一条线段,左端点l即为y+1,右端点r为n-x。
当我们转化成线段以后,这一段线段就表示着分数相同的人数,那么显然,只有与这个线段完全重合的线段是符合要求的,
对于有交集的线段一定是有一个说谎的,但是对于完全重合的线段,还是有可能出现说谎的情况
所以我们可以写个前向星add(b[i].r,b[i].l?1,b[i].w)
l为该区间的左端点,r为该区间的右端点,w为权值
建这个边的原因是f[b[i].r]=max(f[b[i].r],f[b[j].l?1]+e[i].w)
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100007
using namespace std;
int n,tot,num,cnt;
struct node{int l,r,w;}a[N],b[N];
struct node2{int u,v,net,w;}e[N];
int f[N],head[N];
int cmp(node a,node b)
{
if(a.r==b.r)return a.l<b.l;
return a.r<b.r;
}
int cmp2(node a,node b)
{
if(a.r==b.r)return a.w<b.w;
return a.r<b.r;
}
void add(int u,int v,int w)
{
e[++cnt].v=v;e[cnt].w=w;e[cnt].net=head[u];head[u]=cnt;
}
int main()
{
scanf("%d",&n);int x,y,ans=0;
memset(head,-1,sizeof(head)),cnt=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
if(x+y>=n){ans++;continue;}
a[++tot].l=x+1;
a[tot].r=n-y;
}
sort(a+1,a+tot+1,cmp);
for(int i=1;i<=tot;i++)
{
if(a[i].l==a[i-1].l&&a[i].r==a[i-1].r)
{
if(b[num].w<b[num].r-b[num].l+1)
b[num].w++;
}
else b[++num].l=a[i].l,b[num].r=a[i].r,b[num].w=1;
}
sort(b+1,b+num+1,cmp2);
for(int i=1;i<=num;i++) add(b[i].r,b[i].l-1,b[i].w);
int r=0;
int cnt=0;
for(int i=1;i<=n;i++)
{
f[i]=f[i-1];
for(int j=head[i];j!=-1;j=e[j].net)
{
int v=e[j].v;
f[i]=max(f[i],f[v]+e[j].w);
}
}
printf("%d\n",n-f[n]);
}
折花枝,恨花枝,准拟花开人共卮,开时人去时。
怕相思,已相思,轮到相思没处辞,眉间露一丝。