Problem
含 N 个数的 a 数组 a1,a2,⋯,an 和含 M 个数的 b 数组 b1,b2,⋯,bm ,求有多少 a,b 公共子序列(记作 arr, 长为 len )满足 arr1<arr2>arr3<arr4>arr5⋯
Limit
1≤N,M≤2000
1≤ai,bi≤2000
Idea
直接 dp 操作,记 dp[i][j][k]
表示公共子序列以
ai=bj
为结尾,同时为上述波浪序列的波峰/谷的方案数(k=0 表示波谷,k=1表示波峰)。
对应波峰谷条件dp[i][j][k]=∑(dp[prei][prej][!k] | 对应波峰/谷条件) ,即使将 ai=bj 作为优化条件优化后也将达到 O(N4)
考虑通过二维树状数组优化求和,二维树状数组第一维表示枚举的 a 数组的第 i 个数,第二维表示 ai 的值(即 bj=ai 的值) 。
则 dp[i][j][0] = get(i-1, b[j]-1, 1)
和 dp[i][j][1] = get(i-1, 2000, 0) - get(i-1, b[j], 0)
,get(x, y, wavel)
函数为获取二维树状数组所有在矩形 [1,1] -> [x, y]
的数值和(wavel 标识前置状态,由于波谷前必为波峰,波峰前必为波谷)。
若优先枚举 i 后枚举 j ,则可能存在查询树状数组时 arrp 与 arrp+1 错位的情况,故应优先枚举 j ,后枚举 i 。
Code
#include<bits/stdc++.h>
using namespace std;
const int N = 2000 + 10;
const int mod = 998244353;
int T, n, m, a[N], b[N], tree[N][N][2], dp[N][N][2];
int lowbit(int x) { return x & -x; }
void add(int x, int y, int w, int wavel) { //wavel = 0 means next a[i] > a[x] for i > x;
for(int i=x;i<N;i+=lowbit(i))
for(int j=y;j<N;j+=lowbit(j))
(tree[i][j][wavel] += w) %= mod;
}
int get(int x, int y, int wavel) {
int res = 0;
for(int i=x;i;i-=lowbit(i))
for(int j=y;j;j-=lowbit(j))
(res += tree[i][j][wavel]) %= mod;
return res;
}
int main()
{
scanf("%d", &T);
while(T--)
{
memset(tree, 0, sizeof(tree));
memset(dp, 0, sizeof(dp));
scanf("%d %d", &n, &m);
for(int i=1;i<=n;i++)
scanf("%d", &a[i]);
for(int i=1;i<=m;i++)
scanf("%d", &b[i]);
long long ans = 0;
for(int j=1;j<=m;j++)
for(int i=1;i<=n;i++)
{
if(a[i] != b[j]) continue;
(dp[i][j][0] = get(i-1, 2000, 1) - get(i-1, b[j], 1) + 1) %= mod;
(ans += dp[i][j][0]) %= mod;
(dp[i][j][1] = get(i-1, b[j]-1, 0)) %= mod;
(ans += dp[i][j][1]) %= mod;
add(i, b[j], dp[i][j][0], 0);
add(i, b[j], dp[i][j][1], 1);
}
printf("%lld\n", (ans+mod) % mod);
}
}