题目大意:给出一个长度为 $n$ 的序列,问有多少个不同的严格上升子序列(位置不同但元素相同算一种)。$n \leq 10^5$
其实这道题并没有什么思维难度……但是我的树状数组差分写得好不熟练啊……
需要注意在离散化的时候,if (a[i] != a[i-1]) ++cnt; a[i] = cnt;
的代码是不对的,因为 a[i-1]
已经修改过了,应该写成 if (b[i] != b[i-1]) ++cnt; a[i] = cnt;
每次给ans和树状数组加上增量,val应该记录当前值。
#include <cstdio>
#include <algorithm>
const int N = 100005, P = 1e9+7;
struct Node {
int x, y, id;
} a[N];
int sum[N], val[N], vis[N], n;
int read() {
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
x = (x << 3) + (x << 1) + (c ^ 48);
c = getchar();
}
return x * f;
}
bool cmp1(Node a, Node b) {
return a.y < b.y;
}
bool cmp2(Node a, Node b) {
return a.id < b.id;
}
int lowbit(int x) {
return x & (-x);
}
void update(int x, int y) {
while (x <= n) sum[x] = (sum[x] + y) % P, x += lowbit(x);
}
int query(int x) {
int res = 0;
while (x) res = (res + sum[x]) % P, x -= lowbit(x);
return res;
}
int main() {
n = read();
for (int i = 1; i <= n; ++i) a[i].y = read(), a[i].id = i;
std::sort(a + 1, a + n + 1, cmp1);
int cnt = 1; a[1].x = cnt;
for (int i = 2; i <= n; ++i) {
if (a[i].y != a[i-1].y) ++cnt;
a[i].x = cnt;
}
std::sort(a + 1, a + n + 1, cmp2);
int ans = 0;
for (int i = 1; i <= n; ++i) { //核心代码
int now = query(a[i].x - 1), inc = (now - val[a[i].x] + P) % P; //当前值和增量
ans = (ans + inc) % P; //ans加上增量
val[a[i].x] = now; //val记录当前值
update(a[i].x, inc); //树状数组加上增量
if (!vis[a[i].x]) { //树状数组给第一次出现的数加一
update(a[i].x, 1);
vis[a[i].x] = 1;
}
}
printf("%d\n", ans);
return 0;
}
时间复杂度 $O(n \log n)$