【BZOJ2298】[HAOI2011]problem a DP
阿新 • • 發佈:2017-09-24
最大 一起 class min rip ret esc output 並且
2 0
0 2
2 2
【BZOJ2298】[HAOI2011]problem a
Description
一次考試共有n個人參加,第i個人說:“有ai個人分數比我高,bi個人分數比我低。”問最少有幾個人沒有說真話(可能有相同的分數)Input
第一行一個整數n,接下來n行每行兩個整數,第i+1行的兩個整數分別代表ai、bi
Output
一個整數,表示最少有幾個人說謊
Sample Input
32 0
0 2
2 2
Sample Output
1HINT
100%的數據滿足: 1≤n≤100000 0≤ai、bi≤n
題解:先得出每個人可能的名次分布區間[li,ri],然後考慮那些說真話的人的區間是什麽樣。發現最終說真話的人的區間一定呈如下形式:若幹個[l1,r1],若幹個[l2,r2]。。。若幹個[li,ri],並且l1<r1<l2<r2...<li<ri。所以這題本質上就是問你最多能選多少個互不包含的區間。所以將說話相同的人合並到一起,然後用前綴最大值維護s[i],表示右端點為i時,以前最多有多少人說真話即可。
然而我這個沙茶用了樹狀數組。。。。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn=100010; struct node { int a,b; }p[maxn]; int n; int s[maxn]; bool cmp(const node &a,const node &b) { return (a.b==b.b)?(a.a<b.a):(a.b<b.b); } inline void updata(int x,int val) { for(int i=x+1;i<=n+1;i+=i&-i) s[i]=max(s[i],val); } inline int query(int x) { int i,ret=0; for(i=x+1;i;i-=i&-i) ret=max(ret,s[i]); return ret; } inline int rd() { int ret=0,f=1; char gc=getchar(); while(gc<‘0‘||gc>‘9‘) {if(gc==‘-‘)f=-f; gc=getchar();} while(gc>=‘0‘&&gc<=‘9‘) ret=ret*10+gc-‘0‘,gc=getchar(); return ret*f; } int main() { n=rd(); int i,j,a,b; for(i=1;i<=n;i++) a=rd(),b=rd(),p[i].a=b,p[i].b=n-a; sort(p+1,p+n+1,cmp); for(i=1;i<=n;i=j+1) { for(j=i;j<n&&p[j+1].a==p[j].a&&p[j+1].b==p[j].b;j++); if(p[i].a>=p[i].b) continue; updata(p[i].b,query(p[i].a)+min(j-i+1,p[i].b-p[i].a)); } printf("%d",n-query(n)); return 0; }
【BZOJ2298】[HAOI2011]problem a DP