码迷,mamicode.com
首页 > 其他好文 > 详细

P2519 [HAOI2011]problem a

时间:2019-03-18 15:16:11      阅读:131      评论:0      收藏:0      [点我收藏+]

标签:it!   赋权   log   两种   algo   else   printf   algorithm   cond   

思路

神仙思路,就差一步就能想出来了。。。
看到第i个人给出的条件,发现有\(a_i\)个大于,\(b_i\)个小于并不好处理
考虑把条件转化成第i个人对应的排名处理,设第i个人的排名为\(a_i+1\),则应当有\(n-a_i-b_i\)个和第i个人成绩相同的人
数形结合一下
把第i个人的条件看成是一个区间,区间开头是\(a_i+1\),结尾是\(n-b_i\),表示排名在这段区间中的人成绩相等
当两个人说的区间不重叠的时候,两个人都可以被判为真
这里要注意两个区间可以完全重合(两个人分数一致,说的都是一样的)(我就是没考虑这个)
有两种情况不可行(必然是谎言),一是左端点大于右端点,二是有超过区间长度的人都说了一样的话(这样只有区间长度个人说了真话)
于是给每个区间赋权值表示说这个区间的人数,所以要求的就是选出一些不相交区间使得权值最大(选出的人都说真话)
dp一下
转移方程是\(dp[i]=max(dp[i-1],dp[k]+E[i].val)\),k是最后一个右端点小于i的左端点的区间
k可以二分的找到,所以复杂度是\(O(n\log n)\)

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
int n,f[100100],a[100100],b[100100],cnt;
struct Inter{
    int s,t,val;
}E[100100];
bool cmp(Inter a,Inter b){
    return a.t<b.t||(a.t==b.t&&a.s<b.s);
}
int find(int l,int r,int val){
    int midans=0;
    while(l<=r){
        int mid=(l+r)>>1;
        if(E[mid].t<val)
            midans=mid,l=mid+1;
        else
            r=mid-1;
    }
    return midans;
}
map<pair<int,int> , int> M;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d %d",&a[i],&b[i]);
        int len=n-a[i]-b[i];
        int lx=a[i]+1,rx=lx+len-1;
        if(rx>=lx)
            M[make_pair(lx,rx)]=min(rx-lx+1,M[make_pair(lx,rx)]+1);
    }
    for(auto it = M.begin();it!=M.end();it++){
        E[++cnt].s=(*it).first.first;
        E[cnt].t=(*it).first.second;
        E[cnt].val=(*it).second;
    }
    sort(E+1,E+cnt+1,cmp);
    f[1]=E[1].val;
    for(int i=2;i<=n;i++)
        f[i]=max(f[i-1],f[find(1,i-1,E[i].s)]+E[i].val);
    printf("%d\n",n-f[n]);
    return 0;
}

P2519 [HAOI2011]problem a

标签:it!   赋权   log   两种   algo   else   printf   algorithm   cond   

原文地址:https://www.cnblogs.com/dreagonm/p/10552240.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!