hdu--6078--Wavel Sequence(dp)

本文介绍了一道关于寻找两个序列中能构成特定波浪序列的组合的问题,通过动态规划的方法来解决这一挑战。

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

Wavel Sequence

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 479    Accepted Submission(s): 251


Problem Description
Have you ever seen the wave? It's a wonderful view of nature. Little Q is attracted to such wonderful thing, he even likes everything that looks like wave. Formally, he defines a sequence a1,a2,...,an as ''wavel'' if and only if a1<a2>a3<a4>a5<a6...



Picture from Wikimedia Commons


Now given two sequences a1,a2,...,an and b1,b2,...,bm, Little Q wants to find two sequences f1,f2,...,fk(1fin,fi<fi+1) and g1,g2,...,gk(1gim,gi<gi+1), where afi=bgi always holds and sequence af1,af2,...,afk is ''wavel''.

Moreover, Little Q is wondering how many such two sequences f and g he can find. Please write a program to help him figure out the answer.
 

Input
The first line of the input contains an integer T(1T15), denoting the number of test cases.

In each test case, there are 2 integers n,m(1n,m2000) in the first line, denoting the length of a and b.

In the next line, there are n integers a1,a2,...,an(1ai2000), denoting the sequence a.

Then in the next line, there are m integers b1,b2,...,bm(1bi2000), denoting the sequence b.
 

Output
For each test case, print a single line containing an integer, denoting the answer. Since the answer may be very large, please print the answer modulo 998244353.
 

Sample Input
1 3 5 1 5 3 4 1 1 5 3
 

Sample Output
10
题意:

题目给出两个序列a和b,从这两个序列中选出相同数量的数字,按照题目给出的顺序,有如下要求:

1,两个序列相同。

2,所选的序列可以组成波浪序列,即a1<a2>a3<a4>a5<a6...(第一个必须为波谷)。

问:一共有多少种情况满足条件的序列

思路:

运用动态规划思想,枚举a数组每一个元素,作为波浪序列的末尾元素,算出该元素的贡献  进行累加,当然,

每枚举一个a数组元素都要遍历全部的b数组。

dp[j][0]表示以数组b第j个元素结尾为波谷情况数;

dp[j][1]表示以数组b第j个元素结尾为波峰情况数;

sum[j][1]表示以数组b第j个元素(这个数)结尾为波峰‘总’情况数;

sum[j][0]表示以数组b第j个元素(这个数)结尾为波谷‘总’情况数;

因为dp的值是在不断更新着的,用sum数组记录每一次计算的总和。

对于每个a[i],只有b[i]==a[i]时,才有贡献,dp[j][0]记录的是 a[i]==b[j]为波谷的情况;

当b[j]<a[i]时,说明当a[i]被选中时,前面的以b[j]结尾的可以作为 波谷(所以将其记录到cnt0,

又因为前面的作为波谷,所以为sum[j][0]),当b[j]>a[i]时同理。

代码:

 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn = 2e3 + 10;
const int mod = 998244353;

int n, m;
int a[maxn], b[maxn];
ll dp[maxn][2];
ll sum[maxn][2];
int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        ll ans = 0;
        scanf("%d%d", &n, &m);
        memset(sum, 0sizeof(sum));
        memset(dp, 0sizeof(dp));
        for (int i = 1; i <= n; i++)
            scanf("%d", a + i);
        for (int i = 1; i <= m; i++)
            scanf("%d", b + i);

        for (int i = 1; i <= n; i++)
        {
            ll cnt1 = 1;    ///最后一个是波峰的数量,当前的为波谷(当只有一个数时,可以视为波谷)
            ll cnt0 = 0;    ///最后一个是波谷的数量,当前的为波峰(因为是从波谷开始的,所以为零)
            for (int j = 1; j <= m; j++)
            {
                dp[j][0] = dp[j][1] = 0;
                if (a[i] == b[j])   ///当相同时可以将当前的数作为
                    ///波峰(当前数做波峰则看其前面可作为他的波谷的数量cnt0)或波谷(其前cnt1种可能)时,前面所有可能的情况加到ans中
                {
                    dp[j][0] = cnt1;
                    dp[j][1] = cnt0;
                    ans = (ans + cnt1 + cnt0) % mod;
                }
                else if (b[j] < a[i])
                    cnt0 = (cnt0 + sum[j][0]) % mod;    ///说明当a[i]被选中时,前面的以b[j]结尾的可以作为
                ///  波谷(所以将其记录到cnt0,又因为前面的作为波谷,所以为sum[j][0])
                else
                    cnt1 = (cnt1 + sum[j][1]) % mod;    ///反之亦然
            }
            for (int j = 1; j <= m; j++)
            {
                if (b[j] == a[i])
                {
                    sum[j][0] = (sum[j][0] + dp[j][0]) % mod;   ///以数字b[j]作为谷底的所有可能加进去,方便下次统计,

                    sum[j][1] = (sum[j][1] + dp[j][1]) % mod;   ///同理
                }
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值