hdu6078 wave sequence dp

来源:互联网 发布:mac恢复垃圾箱删除文件 编辑:程序博客网 时间:2024/05/17 08:11

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