版权声明:神犇使用记得标明出处哦QAQ https://blog.csdn.net/qq_41717018/article/details/83587783
BZOJ 1109&&DTOJ 1556 堆积木
题目描述
在她的生日礼物中有一些积木。那些积木都是相同大小的立方体。每个积木上面都有一个数。
用他的所有积木垒了一个高塔。 妈妈告诉
游戏的目的是建一个塔,使得最多的积木在正确的位置。一个上面写有数i的积木的正确位置是这个塔从下往上数第
个位置。
决定从现有的高塔中移走一些,使得有最多的积木在正确的位置。请你告诉
她应该移走哪些积木。
输入
输入文件的第一行为一个数
,表示高塔的初始高度。
第二行包含
个数
,表示从下到上每个积木上面的数。
。
输出
请输出最多有多少点可以处在正确位置
样例输入
5
1 1 2 5 4
样例输出
3
题解:
这题很妙(我才不会告诉你我差点就把CDQ打下去了 )
假设有两个点,
同时在一个合法的序列中,并且
在
的后面,
于是通过瞎膜样例,得到满足的条件:
且
因为可以得到,
就是从
号点,走到当前序列起点的消耗。
若
可以满足,要么在点
处直接满足,要么删掉一些点后满足,所以可以得到
很好,三维偏序,
走起。。。
事实并不需要%PoPoQQQ
我们发现
只要满足
且
,就可以满足
惹!!
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);
}