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;
}

浙公网安备 33010602011771号