HDU 5773 The All-purpose Zero 求LIS

求最长上升子序列长度:

单纯的dp时间复杂度是O(n*n)的

dp[i] = max(dp[j]+1); (0=<j<=i-1 && a[i]>a[j])

用二分可以减少查找的时间:时间复杂度:O(n*log(n))

模板:

#define maxn 100010
int a[maxn], b[maxn];

// 二分在b[] 数组里找第一个比num 大的数的位置。
int search_(int num, int low, int high) {
    int mid;
    while(low <= high) {
        mid = (low+high)/2;
        if (num >= b[mid]) low = mid + 1;
        else high = mid - 1;
    }
    return low;
}

int LIS(int n) {
    int i, len, pos;
    b[1] = a[1];
    len = 1;
    for (i=2; i<=n; ++i) {
        if (a[i] > b[len]) {// 如果a[i]比b[]中最大的数还大直接插入到最后。   //如果是非递减序列,改为 >= 即可。
            len = len + 1;
            b[len] = a[i];
        }
        else {
            pos = search_(a[i], 1, len);
            b[pos] = a[i];
        }
    }
    return len;
}

Eg:题目链接:The All-purpose Zero

题意:给一个序列,序列里的0可以代替任何数,问这个序列最长时多少。0也可以代替负数。(如果不可以的话...)

思路:因为0可以代替任何数,所以ans一定是优先选择0的,然后把每个数减掉它前面的0的个数。为什么减0呢... 比如:1 2 0 3 优先选0,3-1=2,... ,这样就变成了1 2 2 ...求最长上升子序列的长度+0的个数。

#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;

#define maxn 100010
int a[maxn], b[maxn];

// 二分在b[] 数组里找第一个比num 大的数的位置。
int search_(int num, int low, int high) {
    int mid;
    while(low <= high) {
        mid = (low+high)/2;
        if (num >= b[mid]) low = mid + 1;
        else high = mid - 1;
    }
    return low;
}

int LIS(int n) {
    int i, len, pos;
    b[1] = a[1];
    len = 1;
    for (i=2; i<=n; ++i) {
        if (a[i] > b[len]) {// 如果a[i]比b[]中最大的数还大直接插入到最后。   //如果是非递减序列,改为 >= 即可。
            len = len + 1;
            b[len] = a[i];
        }
        else {
            pos = search_(a[i], 1, len);
            b[pos] = a[i];
        }
    }
    return len;
}

int main() {
    //freopen("in.cpp", "r", stdin);
    int t;
    scanf("%d", &t);
    int cas = 0;
    while(t--) {
        int n;
        scanf("%d", &n);
        int zeroNum = 0, cnt = 0;
        for (int i=0; i<n; ++i) {
            int temp;
            scanf("%d", &temp);
            if (temp == 0) zeroNum++;
            else {
                temp -= zeroNum;
                a[++cnt] = temp;
            }
        }
        int ans = LIS(cnt) + zeroNum;
        if (cnt == 0) ans -= 1;
        printf("Case #%d: %d\n", ++cas, ans);
    }
    return 0;
}
时间: 2024-12-08 22:59:09

HDU 5773 The All-purpose Zero 求LIS的相关文章

HDU 5773 The All-purpose Zero(O(nlgn)求LIS)

http://acm.hdu.edu.cn/showproblem.php?pid=5773 题意: 求LIS,其中的0可以看做任何数. 思路: 因为0可以看做任何数,所以我们可以先不管0,先求一遍LIS,最后再加上0的个数就可以了.当然,每个数需要减去它前面0的个数. 还有这题如果用dp求LIS是要超时的,从别人那里学习了更快的求LIS的方法. 假设存在一个序列d[1..9] = 2 1 5 3 6 4 8 9 7,可以看出来它的LIS长度为5.n 下面一步一步试着找出它. 我们定义一个序列B

HDU 5773 The All-purpose Zero 脑洞LIS

给定一个序列,里面的0是可以任变的.问变化后最长的LIS的长度 首先,0全部选上是不亏的.这个不知道怎么说,YY一下吧. 最关键的就是解决2 0 0 3 这种问题了. 注意到这个序列的LIS应该是3 也就是你求LIS的时候,是不能包括0的,因为0是最后全部加上去的.这样你求到的LIS只能是1. 再来一组数据 2 0 0 3 0 0 4 这样的LIS是5,也就是你求到的LIS只能是1. 这样的话,只有2 1 0求到的LIS是1了. 也就是每个数减去它前面出现过多少个0,再求一次LIS. 关键要抓住

hdu 5773 The All-purpose Zero 最长上升子序列+树状数组

题目链接:hdu 5773 The All-purpose Zero 官方题解:0可以转化成任意整数,包括负数,显然求LIS时尽量把0都放进去必定是正确的. 因此我们可以把0拿出来,对剩下的做O(nlogn)的LIS,统计结果的时候再算上0的数量. 为了保证严格递增,我们可以将每个权值S[i]减去i前面0的个数,再做LIS,就能保证结果是严格递增的. 个人看法:对于显然把所以0放进去部分我解释一下: 如果0位于最长上升子序列两边,这两个零要加进去是显然的 如果有一个0夹于最长上升子序列之间,那么

hdu 1536 S-Nim 博弈论,,求出SG&#39;函数就可以解决

S-Nim Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4975    Accepted Submission(s): 2141 Problem Description Arthur and his sister Caroll have been playing a game called Nim for some time now

POJ 2135 Farm Tour &amp;&amp; HDU 2686 Matrix &amp;&amp; HDU 3376 Matrix Again 费用流求来回最短路

累了就要写题解,最近总是被虐到没脾气. 来回最短路问题貌似也可以用DP来搞,不过拿费用流还是很方便的. 可以转化成求满流为2 的最小花费.一般做法为拆点,对于 i 拆为2*i 和 2*i+1,然后连一条流量为1(花费根据题意来定) 的边来控制每个点只能通过一次. 额外添加source和sink来控制满流为2. 代码都雷同,以HDU3376为例. #include <algorithm> #include <iostream> #include <cstring> #in

HDU 5773 The All-purpose Zero(DP)

题目链接:点击打开链接 思路: 首先一点:我们把所有0都用上是肯定不亏的. 接下来:我们把剩下的非0数求LIS, 但是, 这些0有可能不能全部插入LIS中, 那么势必要在LIS中剔出一些数. 一个很简单的方法, 我们把每一个数减去他前面的0的个数, 这样, 相当于先为0留出了空间, 因为是全都减小, 相对大小是不变的. 细节参见代码: #include <cstdio> #include <cstring> #include <algorithm> #include &

hdu 5773 最长递增子序列 (nlogn)+贪心

The All-purpose Zero Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 947    Accepted Submission(s): 453 Problem Description ?? gets an sequence S with n intergers(0 < n <= 100000,0<= S[i] &l

HDU 4738 Caocao&#39;s Bridges tarjan求桥

Caocao's Bridges Problem Description Caocao was defeated by Zhuge Liang and Zhou Yu in the battle of Chibi. But he wouldn't give up. Caocao's army still was not good at water battles, so he came up with another idea. He built many islands in the Chan

HDU 4738——Caocao&#39;s Bridges——————【求割边/桥的最小权值】

Caocao's Bridges Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4738 Description Caocao was defeated by Zhuge Liang and Zhou Yu in the battle of Chibi. But he wouldn't give up. Caocao's army st

HDU 4738 Caocao&#39;s Bridges(求价值最小的桥)

Problem Description Caocao was defeated by Zhuge Liang and Zhou Yu in the battle of Chibi. But he wouldn't give up. Caocao's army still was not good at water battles, so he came up with another idea. He built many islands in the Changjiang river, and