1. 程式人生 > 其它 >P2519 [HAOI2011]problem a 題解

P2519 [HAOI2011]problem a 題解

Luogu

Description.

\(n\) 個人,第 \(i\) 個人說有 \(a_i\) 個人成績比他高,有 \(b_i\) 個比他低。
問至少幾個人說謊了。

Solution.

首先考慮每個人說的話本質含義是什麼。
相當於對他來說,第 \(a_i+1\) 個人到第 \(n-b_i\) 人分數相同。
我們分別設 \(l_i=a_i+1,r_i=n-b_i\),那也就是所有所選區間要麼重合要麼互不相連。
然後一個區間最多隻能被重合區間長度次。
那麼直接把重合區間壓縮起來,做一個 dp 即可。

Coding.

點選檢視頹怪程式碼
//是啊,你就是那隻鬼了,所以被你碰到以後,就輪到我變成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),bz=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) bz=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	bz?x=-x:x;
}/*}}}*/
int n,m,F[100005],N;
struct node{int l,r,v;}a[100005],b[100005];
inline char cmp1(node x,node y) {return x.l^y.l?x.l<y.l:x.r<y.r;}
inline char cmp2(node x,node y) {return x.r^y.r?x.r<y.r:x.l<y.l;}
int main()
{
	read(N);for(int i=1;i<=N;i++) read(a[i].l),read(a[i].r),a[i].l++,a[i].r=N-a[i].r;
	sort(a+1,a+N+1,cmp1);for(int i=1;i<=N;i++) if(a[i].l<=a[i].r) b[++m]=a[i];
	for(int i=1;i<=m;i++)
		if(i==1||b[i].l!=b[i-1].l||b[i].r!=b[i-1].r) a[++n]=b[i],a[n].v=1;
		else if(a[n].v<a[n].r-a[n].l+1) a[n].v++;
	sort(a+1,a+n+1,cmp2),F[1]=a[1].v;
	for(int i=2;i<=n;i++)
	{
		int ls=upper_bound(a+1,a+i,(node){0,a[i].l},cmp2)-a-1;
		F[i]=max(F[i-1],F[ls]+a[i].v);
	}
	return printf("%d\n",N-F[n]),0;
}