• [HAOI2011] Problem A


    (n) 个人参加考试,第 (i) 个人说,有 (a_i) 个人分数比他高,(b_i) 个人分数比他低。求至少有多少人说了假话。

    Solution

    (l_i=a_i+1, r_i=n-b_i),则假如第 (i) 个人说了真话,那么与第 (i) 个人分数相同的所有人的名次区间为 ([l_i,r_i])

    • 如果 (l_i>r_i),那么这个人直接删去
    • 如果 ((l_i,r_i)) 相同的人超过了 (r_i-l_i+1) 个,就将多出来的人删去

    在余下的区间中,每个区间设定一个权值 (v) 表示它的重数,现在我们就是要选出若干个不相交的区间使得他们的权值和最大,暴力 dp 即可

    考虑将所有区间先按照右端点排序,依次扫描,设 (f[i]) 为扫描到第 (i) 个区间的最优解,于是我们需要二分找到一个最大的 (k) 使得 (r_k<l_i),则 (f[i]=max(f[i-1],f[k]+v_i))

    另一种方法是,设 (f[i]) 为扫描到 (i) 位置时的最优解,那么仍然按照 (r) 升序枚举所有区间来转移,转移方程为

    [f[r_i]=max(f[r_i], f[l_i-1]+v_i) \ f[i]=max(f[i],f[i-1]) ]

    频繁打错变量名……

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 100005;
    
    struct range {
        int l,r,v;
        bool operator < (const range &b) {
            if(r == b.r) return l < b.l;
            else return r < b.r;
        }
    } s[N],x[N];
    
    int n,a[N],b[N],f[N],ind;
    
    
    signed main() {
        ios::sync_with_stdio(false);
        cin>>n;
        for(int i=1;i<=n;i++) {
            cin>>a[i]>>b[i];
            s[i].l=a[i]+1;
            s[i].r=n-b[i];
        }
        sort(s+1,s+n+1);
        for(int i=1;i<=n;i++) {
            if(s[i].l>s[i].r) continue;
            if(x[ind].l!=s[i].l || x[ind].r!=s[i].r) {
                x[++ind]=s[i];
            }
            x[ind].v++;
        }
        for(int i=1;i<=ind;i++) {
            x[i].v=min(x[i].v,x[i].r-x[i].l+1);
            for(int j=x[i-1].r+1;j<=x[i].r;j++) f[j]=max(f[j],f[j-1]);
            f[x[i].r]=max(f[x[i].r],f[x[i].l-1]+x[i].v);
        }
        int ans=0;
        for(int i=1;i<=n;i++) ans=max(ans,f[i]);
        cout<<n-ans;
    }
    
    
  • 相关阅读:
    Django 同步数据库命令syncdb,makemigrations,migrate
    新mac上安装,查看,设置一些常用的软件
    脚本之文本练习
    hadoop工作流程
    find命令
    awk用法
    apache笔记
    iscsi原理
    nfs服务的配置
    django用户投票系统详解
  • 原文地址:https://www.cnblogs.com/mollnn/p/12390408.html
Copyright © 2020-2023  润新知