http://acm.hdu.edu.cn/showproblem.php?pid=6078
题意:题意很清楚,求满足条件的序列个数
二维dp,dp【i】【j】【k】代表以a【i】,b【j】结尾的形状为k的波浪序列的个数,形状有两种,波峰波谷,也就是要比前一个大或者小的状态
dp【i】【j】【0】=sum(dp【z】【x】【1】)(z<i,x<j&&a[z]>a[i])
dp【i】【j】【1】=sum(dp【z】【x】【0】)(z<i,x<j&&a[z]<a[i])
直接转移的复杂度比较高,利用前缀和思想,s【i】【j】【k】表示以a【z】(0<z<=i),b【j】结尾形状为k的波浪序列个数
s【i】【j】【k】=sum(dp【z】【j】【k】)(z<=i)
枚举a【z】,枚举b【x】,当遇到a【z】等于b【x】时才能转移,且转移的都是符合上述条件的,这样可以在枚举前面的b【x】时就记录下来所有比a【z】大和所有比a【z】小的元素的方案数,这样能把所有满足上面dp转移方程里x<j的都枚举到,通过前缀和又可以把所有满足z<i的也枚举到
这样会发现根本不需要dp【i】【j】【k】
#include<bits/stdc++.h>
using namespace std;
const int maxn=2005;
const int mo=998244353;
long long dp[maxn][maxn][2],s[maxn][maxn][2],a[maxn],b[maxn];
int main()
{
int T_T,i,j,n,m;
cin>>T_T;
while(T_T--)
{
cin>>n>>m;
for(i=1;i<=n;i++)
cin>>a[i];
for(i=1;i<=m;i++)
cin>>b[i];
memset(dp,0,sizeof(dp));
memset(s,0,sizeof(s));
for(i=1;i<=n;i++)
{
long long ans1=1,ans2=0;
for(j=1;j<=m;j++)
{
s[i][j][0]=s[i-1][j][0];
s[i][j][1]=s[i-1][j][1];
if(b[j]==a[i])
{
s[i][j][0]=(s[i][j][0]+ans1)%mo;
s[i][j][1]=(s[i][j][1]+ans2)%mo;
}
else if(b[j]>a[i])
ans1+=s[i-1][j][1];
else
ans2+=s[i-1][j][0];
}
}
long long ans=0;
for(i=1;i<=m;i++)
ans=(ans+s[n][i][0]+s[n][i][1])%mo;
cout<<ans<<endl;
}
return 0;
}