P2519 [HAOI2011]problem a(DP)

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2519 [HAOI2011]problem a(DP)相关的知识,希望对你有一定的参考价值。

P2519 [HAOI2011]problem a(DP)

此题需要先观察出几个性质:

每个人表示的相同排名区间是: [ a i + 1 , n − b i ] [a_i+1,n-b_i] [ai+1,nbi]

1.显然 a i + 1 > n − b i a_i+1>n-b_i ai+1>nbi 必然说假话。

2.且区间相同的人数超过区间长度也是必然说家伙。

利用上面两个条件,我们可以把区间相同的进行合并,权值就是相同的人数。

这样合并后问题转换成了选择若干个不相交的区间,使得权值和最大。

这里必须要选择不相交的区间,因为如果两个区间相交,显然不可能同时说真话。

这个问题可以通过 d p + dp+ dp+二分或者 d p + dp+ dp+线段树 解决,因为 n ≤ 1 0 5 n\\le 10^5 n105,我们也可以把 n n n看作 n n n​个点直接线性转移。

最后答案就是: n − d p [ m ] n-dp[m] ndp[m]

代码参考题解区

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
struct node{int l,r;} p[N];
int n,tot,num,a[N],w[N],L[N],R[N],f[N];
bool cmp(node x,node y)
{
    if(x.r!=y.r) return x.r<y.r;//关键字:右端点 
    return x.l<y.l;//次关键字:左端点 
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
    	int x,y;
        scanf("%d%d",&x,&y);
        if(x+y>=n) continue;//显然是假话(自己体会) 
        p[++tot].l=x+1,p[tot].r=n-y;//记录线段左右端点 
    }
    sort(p+1,p+tot+1,cmp);
    for(int i=1;i<=tot;i++)//计算区间权值
    {
        if(p[i].l!=p[i-1].l||p[i].r!=p[i-1].r) num++;
        //如果线段完全重合则num值不发生变化,权值增加
        w[num]=min(w[num]+1,p[i].r-p[i].l+1);//区间权值
        L[num]=p[i].l,R[num]=p[i].r;//记录重新选出来的线段
    }
    int j=1;
    for(int i=1;i<=n;i++)
    {
        f[i]=f[i-1];
        while(j<=num&&R[j]==i) 
		{
			f[i]=max(f[i],f[L[j]-1]+w[j]);//上文已解释
			j++;
		}
    }
    printf("%d",n-f[n]);
    return 0;
}

以上是关于P2519 [HAOI2011]problem a(DP)的主要内容,如果未能解决你的问题,请参考以下文章

P2519 [HAOI2011]problem a

P2519 [HAOI2011]problem a

p2519 [HAOI2011]problem a

bzoj2301HAOI2011Problem b

BZOJ 2298: [HAOI2011]problem a

BZOJ 2301[HAOI2011]Problem b