【DP】BZOJ2298(HAOI2011)[problem a]

题目概述

n n 个人,第 i 个人说有 ai a i 人排名在他前面, bi b i 个人排名在他后面(可以有相同排名),问最少有几人说谎。

解题报告

i i 个人的排名范围是 [ai+1,nbi] a a 不同或 b 不同的两个人都说真话时区间不能有冲突(否则两人可能为相同排名,这是不可能的)。所以我们可以DP,定义 f[i] f [ i ] 表示前 i i 名最多有多少人说真话,那么每个 (a,b) 都是一条 a1b a − 1 → b 的转移。最后 nf[n] n − f [ n ] 就是答案。

注意同一区间 [x,y] [ x , y ] 中如果人数超过 yx+1 y − x + 1 那么贡献只有 yx+1 y − x + 1

示例程序

#include<cstdio>
#include<algorithm>
#define fr first
#define sc second
using namespace std;
const int maxn=100000;

int n,f[maxn+5];pair<int,int> a[maxn+5];
int E,lnk[maxn+5],nxt[maxn+5],son[maxn+5],w[maxn+5];

#define Add(x,y,z) son[++E]=(y),w[E]=(z),nxt[E]=lnk[x],lnk[x]=E
int main(){
    freopen("program.in","r",stdin);
    freopen("program.out","w",stdout);
    for (int i=(scanf("%d",&n),1);i<=n;i++) scanf("%d%d",&a[i].fr,&a[i].sc);
    sort(a+1,a+1+n);
    for (int i=1,j;i<=n;i=j){
        for (j=i;j<=n&&a[i]==a[j];j++);
        int x=a[i].fr+1,y=n-a[i].sc;if (x>y) continue;
        Add(y,x-1,min(y-x+1,j-i));
    }
    for (int i=1;i<=n;f[i]=max(f[i],f[i-1]),i++)
        for (int j=lnk[i];j;j=nxt[j])
            f[i]=max(f[i],f[son[j]]+w[j]);
    return printf("%d\n",n-f[n]),0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值