BZOJ 1109&&DTOJ 1556 堆积木

版权声明:神犇使用记得标明出处哦QAQ https://blog.csdn.net/qq_41717018/article/details/83587783

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);
}

猜你喜欢

转载自blog.csdn.net/qq_41717018/article/details/83587783