hdu 5489(LIS最长上升子序列)

来源:互联网 发布:编程入门语言 编辑:程序博客网 时间:2024/06/05 11:05

题意:一个含有n个元素的数组,删去k个连续数后,最长上升子序列        /*思路参考GoZy

思路: 4 2 3 [5 7 8] 9 11 ,括号表示要删掉的数,

所以  最长上升子序列  =   ] 右边数A的lis + [左边最大值小于A的lis 

即相当于枚举删除的所有情况,并求它们的LIS,取最大值

如本例 : 最长 = 2[ 9 11]  + 2[2 3],  然后将框从左往右移,算出最大值


用nlog(n)求LIS:

对于a[i],在arr数组中用log(n)找到比它小的数的个数x,arr[x] = a[i] ,arr保存的到当前位置的最长LIS


#include <cstdio>#include <cstring>#include <algorithm>#include <functional>#include <vector>#include <queue>#define MAXN 100010typedef long long ll;using namespace std;const int N = 1e5 + 5;int a[N];int b[N];int d1[N];      //表示i处的LISint arr[N];int main(){    int t,cas = 1;    int n,len;    scanf("%d",&t);    while(t--)    {        scanf("%d%d",&n,&len);        for(int i = 0; i <= n-1; i++)        {            scanf("%d",&a[i]);            b[i] = -a[i];            //为求右边的LIS        }        memset(arr,0x3f3f3f,sizeof(arr));        for(int i = n-1; i >= 0; i--)   //nlog(n)求LIS        {            int x = lower_bound(arr,arr+n,b[i]) - arr;   //用log(n)查找,也可二分            arr[x] = b[i];                                           d1[i] = x+1;        }        int ans = 0,tlen = 0;        memset(arr,0x3f3f3f,sizeof(arr));        for(int i = len; i < n; i++)                        //arr中保存框左边的数最长lis        {            int x = lower_bound(arr,arr+n,a[i]) - arr;     //在前面找最大值比a[i]小的最长LIS            ans = max(ans,x + d1[i]);            x = lower_bound(arr,arr+n,a[i - len]) - arr;                arr[x] =  a[i - len];            tlen = max(x+1,tlen);                           //记录左边的最长长度        }        printf("Case #%d: ", cas++);        ans = max(ans,tlen);                                //比较全在框左边的情况        printf("%d\n",ans);    }    return 0;}



ps.如果没有东西值得你为之努力,那你和一条咸鱼有什么区别? 


0 0
原创粉丝点击