[HAOI2011][BZOJ2298] problem a

2298: [HAOI2011]problem a

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 766  Solved: 346
[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

Sample Output

1

HINT

 

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

首先,要求最少说谎人数,即最大说真话人数。

对于每一个人,有a[i]个比他分数高的,b[i]个比他分数低的。则若序列为单调不增序列,和他同分的人的序号一定在a[i]+1->n-b[i]之间。因此可以想象成一段线段,问题转化为在一个长度为n的线段上有几段线段,求几段不想交的线段的长度之和,使这个值最大。

于是就是一个dp的题目了。方程显而易见。

 

又了解了一个map,在黄学长题解里还看到了动态数组?自己STL好弱……过几天系统学一下。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<map>
using namespace std;
map <pair<int,int>,int> s;
int a,b,n,m,dp[100001],head[100001],next[100001],list[100001];
void add(int x,int y)
{
    next[++m]=head[x];
    head[x]=m;
    list[m]=y;
}
int main()
{
    scanf("%d",&n);
    m=0;
    for (int i=1;i<=n;i++)
    {
        scanf("%d%d",&a,&b);
        if (a+b>=n) continue;
        a++;
        b=n-b;
        if (!s[make_pair(a,b)]) add(b,a);
        s[make_pair(a,b)]=min(s[make_pair(a,b)]+1,b-a+1);
    }
    for (int i=1;i<=n;i++)
    {
        dp[i]=dp[i-1];
        for (int j=head[i];j;j=next[j])
        {
            int u=list[j]-1;
            dp[i]=max(dp[i],dp[u]+s[make_pair(u+1,i)]);
        }
    }
    printf("%d",n-dp[n]);
    return 0;
}

 

posted @ 2015-07-13 20:58  ws_fqk  阅读(158)  评论(0编辑  收藏  举报