(2016多校联赛)HDU5773 The All-purpose Zero

5 篇文章 0 订阅

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5773


题目大意:

给一串序列,要你找最长递增子序列(LIS)的长度(要求严格递增),稍有不同的是,其中的0可以转化为任意的整数(包括负数,比赛时没考虑到=-=)。


解题思路:
题目主体还是LIS,就变个型。因为0可以变成任意整数,那么只要先把0全部拿出来,然后对0除外的序列求LIS,最后再加上0的个数即可。对0除外的序列需要进行处理,如果0在原序列之间,显然就不能最后在LIS的长度上直接加0的个数吧。处理方法是用除0之外的序列的每一位减去该位之前的0的个数,以保证结果严格递增。

求LIS选用nlogn的解法:
假设输入的序列为s,保存LIS的序列为a
1、先将s的第一位放在a序列中
2、向后判断s,如果s[i]大于a的每一位(其实只要判断最后一位),则在a的末尾插入s[i];
      如果s[i]小于a的最后一位,则用s[i]替换a序列中第一个比它大的数(用二分法找这个数)。
3、重复2的步骤。

代码如下:
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <map>

using namespace std;
const int maxn=100002;

int b[maxn];
int a[maxn];
int n;

int main()
{
    int t;
    scanf("%d",&t);
    int z=1;
    while(t--)
    {
        memset(b,-1,sizeof(b));
        cin>>n;
        int x=0,num=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            if(a[i]==0)
            {
                num++;
                continue;
            }
            else
                a[i] -= num;//每位减去它之前的0的个数
            if(a[i]>b[x])
            {
                x++;
                b[x]=a[i];
            }
            else
            {
                //二分法找第一个比它大的数
                int low=1,high=x,mid;
                while ( low <= high )
                {
                    mid = (low + high )/2;
                    if(a[i]<=b[mid]&&a[i]>b[mid-1])
                    {
                        b[mid]=a[i];
                        break;
                    }
                    else if ( b[mid] < a[i])
                        low = mid + 1;
                    else if ( b[mid] > a[i] )
                        high = mid - 1;

                }
            }

        }
        cout<<"Case #"<<z<<": ";
        cout<<x+num<<endl;
        z++;
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值