hdu6078 wave sequence dp

本文解析了HDU 6078题目中波浪序列计数的问题,采用二维DP算法结合前缀和思想,有效地解决了序列计数问题。文章详细阐述了状态定义、状态转移方程及优化过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值