hdu 4521
地址:http://acm.hdu.edu.cn/showproblem.php?pid=4521
题意:中文。。
mark:看网上大部分解题报告都是用线段树,我又不是很懂线段树,后来突然发现有一个人用变种的LIS做的,顿时来了兴致~
普通的LIS要求O(nlgn)的算法的时候,需要维护一个栈,每次元素比较当前栈顶元素,如果大,直接放入栈顶,否则二分查找到第一个大于它的数,替换它,具体证明就不说了。。。本题有一个限定条件是,LIS里面的序列在原数组里面的位置是要大于d的,那么解决办法就是延缓入栈(我自己随便取的名字),就是你每次计算当前元素能够组成的最长子串的时候,二分到它之前所能组成的最大长度后,直接+1就是当前最长长度,然后不要马上去执行入栈操作,当二分完第i+d个元素应得的长度之后,再执行第i个元素的入栈操作,这样就避免了第i,i+1,...,i+d-1个元素对第i+d个元素的影响,具体可以看代码实现~
代码:
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <iostream> #include <algorithm> #include <set> #include <map> #include <vector> #include <queue> #include <stack> #define INF 0x3f3f3f3f using namespace std; typedef long long LL; int n,d,ans; int a[100010]; int dp[100010],aux[100010]; int find(int m) { int fi, la, mid; fi = 0; la = n; while(fi <= la) { mid = (fi+la)>>1; if(aux[mid] < m) fi = mid+1; else la = mid-1; } return la; } int main() { int i,j,k; while(cin >> n >> d) { for(i = 1; i <= n; i++) cin >> a[i]; memset(dp, 0, sizeof(dp)); memset(aux, 0x3f, sizeof(aux)); aux[0] = -1; for(i = 1; i <= n; i++) { j = find(a[i]); dp[i] = j+1; k = i-d; if(k > 0) aux[dp[k]] = min(aux[dp[k]], a[k]); } ans = 0; for(i = 1; i <= n; i++) ans = max(ans, dp[i]); cout << ans << endl; } return 0; }