andre_joy

导航

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

 

posted on 2013-05-04 10:58  andre_joy  阅读(312)  评论(0编辑  收藏  举报