1. 程式人生 > >HDU 2227 Find the nondecreasing subsequences

HDU 2227 Find the nondecreasing subsequences

long long 推出 int tdi 思想 algorithm 優化 lowbit ()

樹狀數組+dp因為今天復習離散化於是手賤加了個離散化

題目大意

意思是給你一段序列,求裏面的最長不下降子序列的長度。

dp思想

這道題的dp方程非常的好推,看完題目的第一眼就已經推出了方程

設dp[i]表示以當前點為終點的序列方案。所以方程是
\[ dp[i] += (i>j\&\&a[i]\ge a[j])? dp[j]+1:1\ans=\sum_{i=1}^{n}dp[i] \]

但是一看這種方法就是\(n^2\)的復雜度,明顯過不了,那怎麽辦呢?

優化

我們知道,我們最後求得一定是一個前綴和的形式,所以這個樹狀數組可以做的很好。

我們先將原數組從小到大排個序,然後尋找它的下標。

為什麽從小到大呢?因為從小到大的話我們求得一定是不下降子序列,那麽決定答案的就是原位置的下標。

我們可以二分查找它的下標,那麽在他下標之前的前綴和一定就是總的方案數。

然後在查詢的前綴合裏加1,就是答案。

不理解?舉個例子。

排序前: 1 2 5 4 3
排序後: 1 2 3 4 5
數組下標: 1 2 5 4 3
首先第一個值是1,它得下標是1,前綴是0,所以方案數是1
第二個值2,下標二,前綴和1,方案數2
下個值3,下標是3,位置是5,前綴和是3,方案數4
下個值4,下標是4,位置是4,前綴和是4,方案數是5
下個值5,下標是5,位置是3,前綴和是3,方案數是4

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
using namespace std;
const int mod = 1000000007;
int c[100001];
int n;
int b[100001],cnt;
LL tree[100001];
int a[100001];
bool cmp(int x,int y) {
    return x<y;
}
int lowbit(int k) {
    return k&(-k);
}
void add(int k,int val) {
    while(k<=n) {
        tree[k]+=val;
        k+=lowbit(k);
    }
}
int ask(int k) {
    int ans=0;
    while(k!=0) {
        ans = (ans+tree[k])%mod ;
        k-=lowbit(k);
    }
    return ans%mod;
}
int main() {
    while(scanf("%d",&n)!=EOF) {
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        memset(c,0,sizeof(c));
        memset(tree,0,sizeof(tree));
        cnt=0;
        for(int i=1; i<=n; i++) scanf("%d",&a[i]),b[i]=a[i];
        sort(b+1,b+1+n,cmp);
        for(int i=1; i<=n; i++) if(b[i]!=b[cnt])b[++cnt]=b[i];
        for(int i=1; i<=n; i++)a[i]=lower_bound(b+1,b+1+cnt,a[i])-b;
        for(int i=1; i<=n; i++)c[i]=a[i];
        sort(a+1,a+1+n,cmp);
        for(int i=1; i<=n; i++) {
            int id=lower_bound(a+1,a+1+n,c[i])-a;
            add(id,ask(id)+1);
        }
        printf("%d\n",ask(n));
    }
}

HDU 2227 Find the nondecreasing subsequences