CF2143D2 思路分享(dp,二维树状数组)

https://codeforces.com/problemset/problem/2143/D2

题意

定义长度为 \(n\) 的序列 \(b\) 为好的:对 \(n\) 个位置二染色,若 \(i\lt j\)\(b_i \gt b_j\),则 \(i,j\) 不能染同样的颜色.

给定长为 \(n\) 的序列 \(a\),求好的子序列的数量,模 \(10^9+7\).

\(1\le n \le 2000\).

思路

好序列的本质为不存在长度 \(\ge 3\) 的严格下降子序列.

考虑 \(dp\),维护最大值 \(u\) 和已形成长度为 \(2\) 的严格下降子序列的第二个元素的最大值 \(v\).

讨论选择 \(a_i\) 的情况(\(a_i \ge v\)):

  • \(u \gt a_i\),此时 \(a_i\) 成为新的 \(v\)\(u\) 不变,即 \(dp[i][u][a_i] += dp[i-1][u][v]\).

  • \(u \le a_i\),此时 \(a_i\) 成为新的 \(u\)\(v\) 不变,即 \(dp[i][a_i][v] += dp[i-1][u][v]\).

暴力转移可以通过 easy version,时间复杂度 \(\mathcal{O}(n^3)\).

仔细观察转移方程,两种情况均有不变量,整理可得:

  • \(u \gt a_i\),枚举 \(u \in (a_i,n]\)\(dp[i][u][a_i] += dp[i-1][u][0\cdots a_i]\).

  • \(u \le a_i\),枚举 \(v \in [0,a_i]\)\(dp[i][a_i][v] += dp[i-1][0\cdots a_i][v]\).

使用二维树状数组维护即可.

时间复杂度 \(\mathcal{O}(n^2\log^2{n})\).

代码

//author:kzssCCC

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

const int MOD = 1e9+7;
	
class fenwick2D{
public:
	int n,m;
	vector<vector<ll>> a;

	fenwick2D(int _n,int _m){
		n = _n;
		m = _m;
		a.assign(n+1,vector<ll>(m+1));
	}

	void update(int x,int y,ll val){
		if (x<1 || x>n || y<1 || y>m) return;
		for (int i=x;i<=n;i+=i&-i){
			for (int j=y;j<=m;j+=j&-j){
				a[i][j] = (a[i][j]+val)%MOD;
			}
		}
	}

	void build(vector<vector<ll>>& b){
		a = b;
		for (int i=1;i<=n;i++){
			for (int j=1;j<=m;j++){
				int nj = j+(j&-j);
				if (nj<=m){
					a[i][nj] = (a[i][nj]+a[i][j])%MOD;
				}
			}
		}		

		for (int j=1;j<=m;j++){
			for (int i=1;i<=n;i++){
				int ni = i+(i&-i);
				if (ni<=n){
					a[ni][j] = (a[ni][j]+a[i][j])%MOD;
				}
			}
		}
	}

	ll query(int x,int y){
		if (x<1 || x>n || y<1 || y>m) return 0;
		ll res = 0;
		for (int i=x;i>=1;i-=i&-i){
			for (int j=y;j>=1;j-=j&-j){
				res = (res+a[i][j])%MOD;		
			}
		}
		return res;
	}

	ll query_range(int x1,int y1,int x2,int y2){
		if (x1<1 || x1>n || x2<1 || x2>n || y1<1 || y1>m || y2<1 || y2>m || x1>x2 || y1>y2) return 0;
		return (((query(x2,y2)-query(x2,y1-1)+MOD)%MOD-query(x1-1,y2)+MOD)%MOD+query(x1-1,y1-1))%MOD;	
	}
};

void solve(){
	int n;
	cin >> n;

	vector<int> a(n+1);
	for (int i=1;i<=n;i++){
		cin >> a[i];
	}

	fenwick2D fw(n+1,n+1);
	fw.update(1,1,1);
	for (int i=1;i<=n;i++){
		for (int u=a[i]+1;u<=n;u++){
			fw.update(u+1,a[i]+1,fw.query_range(u+1,1,u+1,a[i]+1));
		}
		for (int v=0;v<=a[i];v++){
			fw.update(a[i]+1,v+1,fw.query_range(1,v+1,a[i]+1,v+1));
		}
	}

	cout << fw.query(n+1,n+1) << '\n';
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int t = 1;
	cin >> t;
	while (t--) solve();

	return 0;
}
posted @ 2026-06-22 18:56  kzssCCC  阅读(4)  评论(0)    收藏  举报