[Ybt High-Efficiency Advanced 4-2-3] [luogu UVA12983] Strictly ascending number of subsequences / The Battle of Chibi

The number of strictly ascending subsequences / The Battle of Chibi

Topic link: ybt high-efficiency advanced 4-2-3 / luogu UVA12983

General idea

You are required to find the number of strictly ascending subsequences of length m in a sequence.
The number is modulo 1e9+7.

Ideas

First of all, when you see the number of ascending subsequences (that is, the number of pairs in reverse order), you will think of using tree arrays.

Then we consider combining it with DP (because it has a fixed length).

Then we set fi, j f_{i,j}fi,jFor the iiStrictly ascending subsequence at the end of the number i , its length isjjj , how many such are there.

Then it is easy to make a transfer: fi, j = ∑ ak <ai, k <i (fk, j − 1) f_{i,j}=\sum\limits_{a_k<a_i,k<i}(f_{k, j-1})fi,j=ak<ai,k<i(fk,j1)
Then we enumeratei, ji, ji,j forkkk we can use a tree array to get it.

Because it needs a tree array, it needs to be discretized.

The time complexity is O (n 2 logn) O(n^2logn)O ( n2 logn), because it is relatively tight, judge it when taking the modulus before taking it.

Code

#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define mo 1000000007

using namespace std;

struct node {
    
    
	int x, num, lx;
}a[1001];
int T;
int n, m;
ll ans, tree[1001][1001], dp[1001][1001];

void csh() {
    
    
	ans = 0;
	memset(tree, 0, sizeof(tree));
}

bool cmp1(node x, node y) {
    
    
	return x.x < y.x;
}

bool cmp2(node x, node y) {
    
    
	return x.num < y.num;
}

void lsh() {
    
    
	sort(a + 1, a + n + 1, cmp1);
	
	int tmp = 0;
	a[1].lx = ++tmp;
	for (int i = 2; i <= n; i++)
		if (a[i].x == a[i - 1].x) a[i].lx = tmp;
			else a[i].lx = ++tmp;
	
	sort(a + 1, a + n + 1, cmp2);
}

void add(int x, int y, int z) {
    
    //树状数组
	for (; x <= n; x += x & (-x)) {
    
    
		tree[x][y] += z;
		if (tree[x][y] > mo) tree[x][y] -= mo;
	}
}

ll ask(int x, int y) {
    
    
	ll re = 0;
	for (; x; x -= x & (-x)) {
    
    
		re += tree[x][y];
		if (re > mo) re -= mo;
	}
	return re;
}

int main() {
    
    
	scanf("%d", &T);
	for (int times = 1; times <= T; times++) {
    
    
		csh();//初始化
		
		scanf("%d %d", &n, &m);
		for (int i = 1; i <= n; i++) {
    
    
			scanf("%d", &a[i].x);
			a[i].num = i;
		}
		
		lsh();//离散化
		
		for (int i = 1; i <= n; i++) {
    
    
			for (int j = 1; j <= m; j++) {
    
    
				if (j == 1) dp[i][j] = 1;//长度为1,直接方案数为1
					else {
    
    
						dp[i][j] = ask(a[i].lx - 1, j - 1);
						if (dp[i][j] > mo) dp[i][j] -= mo;//不要直接取模
					}
				add(a[i].lx, j, dp[i][j]);
			}
		}
		
		for (int i = m; i <= n; i++) {
    
    
			ans += dp[i][m];//看这个子序列最后是哪个结尾的个数
			if (ans > mo) ans -= mo;
		}
		
		printf("Case #%d: %lld\n", times, ans);
	}
	
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_43346722/article/details/114772037