Description
BZOJ5157
Luogu3970
求原序列有多少个上升子序列。
Solution
本来想先暴力DP一下拿个部分分,但是由于不会去重,这个思路就破灭了。
后来手玩的时候突然发现,不就是把比这个数小的答案都加起来就是它的答案了啊,形式化的说就是\(f_i=\sum f_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;
}