题目链接:HDU4521
【分析】看到了LIS+线段树才会写的,还是太弱;这个其实就是LIS稍微变化了一下,DP方程变成了dp[i] = max{dp[j]}+1 (0 <= j < i-d-1 && a[j] < a[i]);直接这样做复杂度是O(n^2)的,数据量为10^5,必然超时。看到max{dp[j]}就想到了可以用线段树来优化,用线段树存max{dp[j]},线段树的区间用a[]的值表示,这样询问[ 0,a[i]-1 ]就保证了a[j] < a[i],但是由于需要隔开d个位置,所以加入dp[i]的时候更新dp[i+d+1]就保证了[i,i+d]这段还没被加入线段树,这样最后答案就是max{dp[]}。
【AC CODE】421ms
#include <cstdio> #include <cstring> #include <cctype> #include <cmath> #include <map> //#include <unordered_map> #include <queue> #include <stack> #include <vector> #include <string> #include <algorithm> using namespace std; typedef long long LL; #define rep(i,a,n) for(int i = a; i < n; i++) #define repe(i,a,n) for(int i = a; i <= n; i++) #define per(i,n,a) for(int i = n; i >= a; i--) #define clc(a,b) memset(a,b,sizeof(a)) #define id(x,y) ((x)+(y)|(x)!=(y)) const int INF = 0x3f3f3f3f, MAXN = 100000+10; int mx[MAXN<<1];//线段树维护值(a[])的区间最大的序列长度(dp[]) inline void push_up(int x, int y, int m){ mx[id(x,y)] = max(mx[id(x,m)],mx[id(m+1,y)]); } int p,v; void update(int x, int y) { if(x == y) { mx[id(x,y)] = max(mx[id(x,y)],v); return; } int m = (x+y)>>1; if(p <= m) update(x,m); else update(m+1,y); push_up(x,y,m); } int ql,qr; int query(int x, int y) { if(ql <= x && y <= qr) return mx[id(x,y)]; int m = (x+y)>>1, ans = 0; if(ql <= m) ans = max(ans,query(x,m)); if(qr > m) ans = max(ans,query(m+1,y)); return ans; } int dp[MAXN], a[MAXN]; int main() { #ifdef SHY freopen("e:\\1.txt", "r", stdin); #endif int n,d; while(~scanf("%d %d*c", &n, &d)) { int ma = 0; rep(i,0,n) scanf("%d%*c", &a[i]), ma = max(ma,a[i]); if(d >= n) { puts("1"); continue; } clc(mx,0); repe(i,0,d) dp[i] = 1; int ans = 1; rep(i,0,n-d-1) { p = a[i];v = dp[i]; update(0,ma); if(!a[i+d+1]) { dp[i+d+1] = 1; continue; } ql = 0, qr = a[i+d+1]-1; dp[i+d+1] = query(0,ma)+1; ans = max(ans,dp[i+d+1]); } printf("%d\n", ans); } return 0; }