bzoj 2298 problem a

Written with StackEdit.

Description

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

Input

第一行一个整数\(n\),接下来\(n\)行每行两个整数,第\(i+1\)行的两个整数分别代表\(a_i,b_i.\)

Output

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

Sample Input

3

2 0

0 2

2 2

Sample Output

1

HINT

\(100\%\)的数据满足: \(1≤n≤100000 0≤a_i,b_i≤n.\)

Solution

  • 一句话题面系列...
  • 关键在于条件的转化.有\(a\)个人严格比他大,\(b\)个人严格比他小,
  • 若将分数从大到小排序,如果这句话为真,那么易知:
  • 性质1这个人的分数一定属于\([a+1,n-b]\),且这个区间内所有人的分数都相同.
  • 性质2这个区间外的分数都与区间内的分数不同.
  • 首先可以排除掉区间左端点大于右端点的人,这些话一定为假.
  • 对于剩下的人,我们假设这些话都为真,可以得到若干个区间.
  • 如果两个区间相交,而又不完全重合,将这两个区间并起来显然可以得到更大的分数相同区间,不符合性质2.而对于完全相同的两个区间,而根据性质1,针对这个区间的话,最多可以有\(r-l+1\)(区间长度)句话为真.
  • 那么可以给每个区间赋一个权值,为这个区间的重复次数与区间长度的最小值.我们现在选出若干个不相交的区间,这些区间的最大权值和即为最多说真话的人数.
  • 这里就是一个\(dp\)了.优化方法多样,我选择无需思考的树状数组.
#include<bits/stdc++.h>
using namespace std;
typedef long long LoveLive;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>'9'||jp<'0')&&jp!='-')
        jp=getchar();
    if (jp=='-')
        {
            fh=-1;
            jp=getchar();
        }
    while (jp>='0'&&jp<='9')
        {
            out=out*10+jp-'0';
            jp=getchar();
        }
    return out*fh;
}
const int MAXN=1e5+10;
int n,tot,unitot;
struct sec{
    int l,r;
    int w;
    bool operator < (const sec& rhs) const
        {
            return r==rhs.r?l<rhs.l:r<rhs.r;
        }
}s[MAXN],p[MAXN];
#define lowbit(x) x&(-x)
int bit[MAXN];
inline void upd(int x,int c)
{
    for(;x<=n;x+=lowbit(x))
        bit[x]=max(bit[x],c);   
}
inline int query(int x)
{
    if(x<=0)
        return 0;
    int res=0;
    for(;x;x-=lowbit(x))
        res=max(res,bit[x]);
    return res;
}
void UniqueSec()
{
    for(int i=1;i<=tot;++i)
        {
            if(i==1 || s[i].l!=s[i-1].l || s[i].r!=s[i-1].r)
                ++unitot;
            p[unitot].w=min(p[unitot].w+1,p[unitot].r-p[unitot].l+1);
            p[unitot].l=s[i].l;
            p[unitot].r=s[i].r;
        }
}
int main()
{
    n=read();
    for(int i=1;i<=n;++i)
        {
            int a=read(),b=read();
            int l=a+1;
            int r=n-b;
            if(l<=r)
                {
                    s[++tot].l=l;
                    s[tot].r=r;
                }
        }
    sort(s+1,s+1+tot);
    UniqueSec();
    for(int i=1;i<=unitot;++i)
        {
            int l=p[i].l,r=p[i].r;
            int val=query(l-1)+p[i].w;
            upd(r,val);
        }
    int ans=n-query(n);
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/jklover/p/10108787.html