1. 程式人生 > >[TJOI2014]上升子序列

[TJOI2014]上升子序列

c++ sum class n) script 去重 %d lower www.

Description

BZOJ5157
Luogu3970
求原序列有多少個上升子序列。

Solution

本來想先暴力DP一下拿個部分分,但是由於不會去重,這個思路就破滅了。
後來手玩的時候突然發現,不就是把比這個數小的答案都加起來就是它的答案了啊,形式化的說就是\(f_i=\sum a_j (j < i,a_j<a_i)\)
這樣的話離散化一下樹狀數組求前綴和就可以水過了...

Code

#include <cstdio>
#include <algorithm>

const int N = 1e5 + 10;
const int MOD = 1e9 + 7;

int f[N], a[N], b[N], n, c[N];

void add(int p, int x) {
    while (p <= n) {
        f[p] = (f[p] + x) % MOD;
        p += p&-p;
    }
}

int query(int p) {
    int ans = 0;
    while (p > 0) {
        ans = (ans + f[p]) % MOD;
        p -= p&-p;
    }
    return ans;
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
        c[i] = a[i];
    }
    std::sort(c+1, c+n+1);
    int now = std::unique(c+1, c+n+1) - c;
    for (int i = 1; i <= n; ++i) {
        b[i] = std::lower_bound(c+1, c+now, a[i]) - c;
    }
    for (int i = 1; i <= n; ++i) {
        int ans = query(b[i]-1)+1;
        add(b[i], (query(b[i])-query(b[i]-1)+MOD)%MOD*-1);
        add(b[i], ans);
    }
    int ans = (query(n) - now + 1 + MOD) % MOD;
    printf("%d\n", ans);
    return 0;
}

[TJOI2014]上升子序列