题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6078
题意:定义一种波浪数列,满足a1< a2 > a3 < a4 > a5
给两个数列a,b,选出a b的一个公共子串,且是一个波浪数列,问这样的方案有多少种。
因为每一次枚举a[i] 的时候都是重新计算了一次dp[j][0] 和 dp[j][1] ,所以sum[j][0] 计算的是每次计算的总和。
只有当a[i]==a[j] 的时候才会有贡献值,对于dp[j][0] 来说,当a[i]==a[j] 的时候,它是为谷底的情况,那么只需要把之前已经算出的a[i] < b[k]已经存在的情况在加上a[i] 就是一个新的满足条件的序列。 dp[j][1] 同理。每次dp之后要记录sum[j] 的值。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MOD = 998244353;
const int N = 2e3+5;
int b[N], a[N];
LL sum[N][2], dp[N][2];
int main()
{
int T, n, m;
scanf("%d", &T);
while(T--)
{
memset(sum, 0, sizeof(sum));
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]);
LL ans = 0;
//sum[j][0](sum[j][1])就是在j这个位置,一共有多少种情况让b[j]做波谷(波峰).
//dp[j][0](dp[j][1])代表以b[j]结尾的波谷()波峰。
for(int i = 1; i <= n; i++)
{
LL cnt1 = 1, cnt0 = 0;
for(int j = 1; j <= m; j++)
{
dp[j][0] = dp[j][1] = 0;
if(a[i] == b[j])
{
dp[j][0] = cnt1;
dp[j][1] = cnt0;
ans = (ans+cnt1+cnt0)%MOD;
}
//sum会记下b[j] = a[i]时的可能,而b[j] < a[i]说明b[j]可以在找到下一次相等时做波谷
else if(b[j] < a[i]) (cnt0 += sum[j][0]) %= MOD;
else (cnt1 += sum[j][1]) %= MOD;
}
//累加更新
for(int j = 1; j <= m; j++)
{
if(b[j] == a[i])
{
(sum[j][0] += dp[j][0]) %= MOD;
(sum[j][1] += dp[j][1]) %= MOD;
}
}
}
printf("%lld\n", ans);
}
return 0;
}