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,n−bi]
1.显然 a i + 1 > n − b i a_i+1>n-b_i ai+1>n−bi 必然说假话。
2.且区间相同的人数超过区间长度也是必然说家伙。
利用上面两个条件,我们可以把区间相同的进行合并,权值就是相同的人数。
这样合并后问题转换成了选择若干个不相交的区间,使得权值和最大。
这里必须要选择不相交的区间,因为如果两个区间相交,显然不可能同时说真话。
这个问题可以通过 d p + dp+ dp+二分或者 d p + dp+ dp+线段树 解决,因为 n ≤ 1 0 5 n\\le 10^5 n≤105,我们也可以把 n n n看作 n n n个点直接线性转移。
最后答案就是: n − d p [ m ] n-dp[m] n−dp[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)的主要内容,如果未能解决你的问题,请参考以下文章