1. 程式人生 > >The All-purpose Zero(喜歡這道題)

The All-purpose Zero(喜歡這道題)

The All-purpose Zero

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 553    Accepted Submission(s): 267



Problem Description ?? gets an sequence S with n intergers(0 < n <= 100000,0<= S[i] <= 1000000).?? has a magic so that he can change 0 to any interger(He does not need to change all 0 to the same interger).?? wants you to help him to find out the length of the longest increasing (strictly) subsequence he can get.
Input The first line contains an interger T,denoting the number of the test cases.(T <= 10)
For each case,the first line contains an interger n,which is the length of the array s.
The next line contains n intergers separated by a single space, denote each number in S.

Output For each test case, output one line containing “Case #x: y”(without quotes), where x is the test case number(starting from 1) and y is the length of the longest increasing subsequence he can get.
Sample Input 2 7 2 0 2 1 2 0 5 6 1 2 3 3 0 0
Sample Output Case #1: 5 Case #2: 5 Hint
In the first case,you can change the second 0 to 3.So the longest increasing subsequence is 0 1 2 3 5.
Author FZU
Source 2016 Multi-University Training Contest 4
//標程思想:
/*
0可以轉化成任意整數,包括負數,顯然求LIS時儘量把0都放進去必定是正確的。
因此我們可以把0拿出來,對剩下的做O(nlogn)的LIS,統計結果的時候再算上0的數量。
為了保證嚴格遞增,我們可以將每個權值S[i]減去i前面0的個數(削平它們~),再做LIS,就能保證結果是嚴格遞增的。
*/
#include <iostream>
#include <cstdio>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <utility>
#include <algorithm>
using namespace std;

const int maxn = 1e5+50;
const int INF = 0x3f3f3f3f;
int a[maxn], b[maxn], dp[maxn];

void fil()
{
    for (int i=0; i<maxn; i++)
    {
        dp[i] = INF;
    }
}

int main()
{
    int t;
    int n;
    int k =0;
    int zeron;
    cin >> t;
    while (t--)
    {
        zeron = 0;
        fil();
        cin >> n;
        for (int i=0; i<n; i++)
        {
            cin >> a[i];
        }
        int j = 0;
        for (int i=0; i<n; i++)
        {
            if (0 == a[i])
            {
                zeron++;
            }
            else
            {
                a[i] -= zeron;
                b[j++] = a[i];
            }
        }
        for (int i=0; i<j; i++)
        {
            *lower_bound(dp, dp+n, b[i]) = b[i];
        }
        int ans = lower_bound(dp, dp+n, INF)-dp;
        ans += zeron;

        cout << "Case #" << ++k << ": " << ans << endl;
    }
    return 0;
}

//王剛大神思想:
/*
設一個底線dp[0](一定( ⊙ o ⊙ )!要足夠小哦,o(>﹏<)o不然會Wrong到死的~~);
遇到0的時候才更新dp陣列, 不然會超時的說, 後面一個數比前一個數大一, 保證它是嚴格上升的, 而且要倒著來, 不然就gg啦~~;
變零要比不變的好~\(≧▽≦)/~啦啦啦~~
*/
#include <iostream>
#include <cstdio>
#include <vector>
#include <map>
#include <set>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <utility>
#include <algorithm>
using namespace std;

const int maxn = 1e5+50;
const int INF = 0x3f3f3f3f;

int dp[maxn], a[maxn];
int n;

void fil()
{
    dp[0] = -INF;  //這個要足夠小~
    for (int i=1; i<maxn; i++)
    {
        dp[i] = INF;
    }
}

int main()
{
    int t;
    int k = 0;
    cin >> t;
    while (t--)
    {
        fil();
        cin >> n;
        for (int i=0; i<n; i++)
        {
            scanf("%d", &a[i]);
        }
        for (int i=0; i<n; i++)
        {
            if (0 == a[i])
            {
                *lower_bound (dp, dp+n+1, INF) = dp[lower_bound (dp, dp+n+1, INF)-dp-1]+1; //0放到dp數組裡頭只要比dp數組裡最後一個元素大一就好啦~
            }
            else
            {
                *lower_bound (dp, dp+n+1, a[i]) = a[i];
            }

            if (0 == a[i])
            {
                for (int j=lower_bound (dp, dp+n+1, INF)-dp-1; j>=1; j--)
                {
                    dp[j] = dp[j-1]+1;
                }
            }
        }
        int ans = lower_bound (dp, dp+1+n, INF) - dp - 1;
        cout << "Case #" << ++k << ": " << ans << endl;
    }
    return 0;
}
通過這一題倒是學到了挺多東西的說, 舉幾個栗子給你們……
首先吧,while迴圈裡頭用cin 超時的可能性更大, 最好改成scanf的說~
然後,,別看到二層迴圈就以為是n*n的複雜度呀, 你也要看看具體條件呀, 人家也有可能是n*logn, 或者只要滿足一個條件才會執行內層迴圈!
最後呢,, 心得感悟,,我不說話~
最後, 據說這道題還闊以用線段樹和樹狀陣列來做, 讓我先學一波再來更新部落格~~啊, 好像是有點幹勁啦~開心O(∩_∩)O~~