【DP】#1109. [POI2007]堆积木Klo

https://darkbzoj.cc/problem/1109

分析

考虑状态表示原来在位置 \(i\) 的数有贡献(也就是说在结束操作后它的位置 \(i'\) 满足 \(i'= w_i\))的最大值为 \(f[i]\)

那么我们有转移方程 \(f[i] = \max f[j] + 1\),其中 \((j<i, ~ w_j<w_i, ~ w_i-w_j\leq i-j)\)

考虑优化转移:

\(w_i-w_j \leq i-j\) 也就是 \(j-w_j \leq i-w_i\)

可以发现 \(w_j<w_i, ~ j-w_j \leq i-w_i\) 同时满足的时候第一个约束也必然满足,所以只需要考虑这两个约束。

因为 \(j-w_j \leq i-w_i\) 有等号,为了消除等号的影响,考虑根据 \(j-w_j < i-w_i\) 为第一关键字,下标为第二关键字进行排序。

排序后使用树状数组维护 \(w_j<w_i\) 的贡献即可。

#include<bits/stdc++.h>
using namespace std;
 
#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define all(x) (x).begin(), (x).end()
 
#define x first
#define y second
using pii = pair<int, int>;
using ll = long long;
 
inline void read(int &x){
    int s=0; x=1;
    char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    x*=s;
}

const int N=1e6+5;

int n;

struct Node{
	int id, w;
	
	bool operator < (const Node &o)const{
		return id-w==o.id-o.w? id<o.id: id-w<o.id-o.w;
	}
}w[N];

int tr[N];

int lowbit(int x){
	return x&-x;
}

void upd(int x, int k){
	for(; x<N; x+=lowbit(x)) tr[x]=max(tr[x], k);
}

int query(int x){
	int res=0;
	for(; x; x-=lowbit(x)) res=max(res, tr[x]);
	return res;
}

signed main(){
	cin>>n;
	rep(i,1,n){
		int x; read(x);
		w[i]={i, x};
	}
	sort(w+1, w+1+n);
	
	int res=0;
	rep(i,1,n){
		if(w[i].w>w[i].id) continue;
		int mx=query(w[i].w-1);
		res=max(res, mx+1);
		upd(w[i].w, mx+1);
	}
	cout<<res<<endl;
	
	return 0;
}
posted @ 2022-08-19 18:55  HinanawiTenshi  阅读(17)  评论(0编辑  收藏  举报