[TJOI2014]上升子序列

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;
}
posted @ 2018-09-13 21:23  wyxwyx  阅读(125)  评论(0编辑  收藏  举报