1. 程式人生 > >BZOJ 1109&&DTOJ 1556 堆積木

BZOJ 1109&&DTOJ 1556 堆積木

BZOJ 1109&&DTOJ 1556 堆積木
題目描述
M a r y Mary 在她的生日禮物中有一些積木。那些積木都是相同大小的立方體。每個積木上面都有一個數。 M

a r y Mary 用他的所有積木壘了一個高塔。 媽媽告訴 M a r y
Mary
遊戲的目的是建一個塔,使得最多的積木在正確的位置。一個上面寫有數i的積木的正確位置是這個塔從下往上數第 i i 個位置。 M a r
y Mary
決定從現有的高塔中移走一些,使得有最多的積木在正確的位置。請你告訴 M a r y Mary 她應該移走哪些積木。

輸入
輸入檔案的第一行為一個數 n n ,表示高塔的初始高度。

第二行包含 n n 個數 a 1 , a 2 , . . . , a n a_{1},a_{2},...,a_{n} ,表示從下到上每個積木上面的數。
( 1 n 100000 , 1 a i 1000000 ) (1\leq n\leq100000,1\leq a_{i}\leq1000000)

輸出
請輸出最多有多少點可以處在正確位置

樣例輸入
5
1 1 2 5 4
樣例輸出
3

題解:

這題很妙(我才不會告訴你我差點就把CDQ打下去了
假設有兩個點, i , j i,j 同時在一個合法的序列中,並且 j j i i 的後面,
於是通過瞎膜樣例,得到滿足的條件:
i < j i<j a i < a j a_{i}<a_{j}
因為可以得到, i a i i-a_{i} 就是從 1 1 號點,走到當前序列起點的消耗。
j j 可以滿足,要麼在點 j j 處直接滿足,要麼刪掉一些點後滿足,所以可以得到
j a j > = i a i j-a_{j}>=i-a_{i}
很好,三維偏序, C D Q CDQ 走起。。。
事實並不需要%PoPoQQQ
我們發現 i = ( i a i ) + a i i=(i-a_{i})+a_{i}
只要滿足 j a j > = i a i j-a_{j}>=i-a_{i} a j > a i a_{j}>a_{i} ,就可以滿足 i < j i<j 惹!!
orzorzorzPoPoQQQ

#include<bits/stdc++.h>
using namespace std;
#define in inline
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repd(i,a,b) for(int i=a;i>=b;i--)
#define For(i,a,b) for(int i=a;i<b;i++)
#define _(d) while(d(isdigit(ch=getchar())))
template<class T>in void g(T&t){T x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=x*10+ch-48;t=f*x;}
const int N=1e5+4,M=1e6+4;
struct A{int x,y;}a[N];
int n,mx;
bool cmp(A t1,A t2){
	return t1.y<t2.y||(t1.y==t2.y&&t1.x<t2.x);
}
int t[M],f[M];
in void ins(int x,int v){
	if(x<0) return;
	for(;x<=mx;x+=x&-x) t[x]=max(t[x],v);
}
in int q(int x){
	int res=0;
	for(;x;x-=x&-x) res=max(res,t[x]);
	return res;
}
int main(){
	g(n);
	rep(i,1,n) g(a[i].x),a[i].y=i-a[i].x,mx=max(mx,a[i].x);
	sort(a+1,a+1+n,cmp);int ans=0;
	rep(i,1,n){
		if(a[i].y<0) continue;
		f[i]=q(a[i].x-1)+1;
		ins(a[i].x,f[i]);
		ans=max(ans,f[i]);
	}
	return !printf("%d\n",ans);
}