1. 程式人生 > 其它 >熱身訓練2 The All-purpose Zero

熱身訓練2 The All-purpose Zero

The All-purpose Zero

簡要題意:

長度為n的陣列,每個數字為S[i],$0$是一種很神奇的數字,你想要的,它都可以變!

問這個序列的最長上升子序列長度為多少?

分析:

我們將除了‘0’以外的S[i],減去i之前出現的‘0’的個數,最後求得排除‘0’後的最長上升子序列長度,加上‘0’的個數,就是我們要求的答案。

在這裡我不主要分析該做法的正確性,我們引入一個O(nlogn)的方法來求最長上升子序列。

LIS(點此看題)

貪心+二分

我們令f[i]表示長度為i的上升子序列,末尾的最小值。

這裡我們因為貪心,所以子序列末尾越小越好。

我們按順序列舉給出的陣列S[i],然後對f[]二分查詢除小於S[i]的最大的f[j],並用它將f[j+1]更新。

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define LL long long
const int N=1e5+5;
int n, a[N], b[N], len;
signed main()
{
    scanf("%d",&n);
    for(re i=1;i<=n;++i) scanf("%d",&a[i]);
    for(re i=1;i<=n;++i)
    {
        if(a[i] > b[len]) b[++len] = a[i];
        
else { int tp = lower_bound(b+1, b+1+len, a[i])-b; b[tp] = a[i]; } } printf("%d", len); }

上馬

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define LL long long
const int N=1e5+5;
int n, a[N], b[N], num, len;
inline void work()
{
    num 
= len = 0; scanf("%d",&n); for(re i=1;i<=n;++i) { scanf("%d",&a[i]); if(a[i] == 0) { num ++; a[i] = 1e9; } else { a[i] -= num; } } b[0] = -1e9; for(re i=1;i<=n;++i) { if(a[i] == 1e9) continue; if(a[i] > b[len]) b[++len] = a[i]; else { int tp = lower_bound(b+1, b+1+len, a[i])-b; b[tp] = a[i]; } } printf("%d\n", len+num); } signed main() { int T; scanf("%d",&T); for(re i=1;i<=T;++i) { printf("Case #%d: ",i); work(); } return 0; }
View Code