2017 ACM暑期多校联合训练

题目链接

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 a1a3a5<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(1≤fi≤n,fi<fi+1) and g1,g2,...,gk(1≤gi≤m,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(1≤T≤15), denoting the number of test cases.

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

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

Then in the next line, there are m integers b1,b2,...,bm(1≤bi≤2000), 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

Hint
(1)f=(1),g=(2).
(2)f=(1),g=(3).
(3)f=(2),g=(4).
(4)f=(3),g=(5).
(5)f=(1,2),g=(2,4).
(6)f=(1,2),g=(3,4).
(7)f=(1,3),g=(2,5).
(8)f=(1,3),g=(3,5).
(9)f=(1,2,3),g=(2,4,5).
(10)f=(1,2,3),g=(3,4,5).

题意:
给定数组a和数组b,数组a与数组b中的元素要分别构成“小 大 小 大 小”这样的序列,注意第一个必须是较小的数,问数组a和数组b构成这样一样的序列一共有多少种情况。

分析:
我们考虑到任意的一个数都可以作为起始的那个波谷(相当于它作为第一个数),所以说这样的话以任意一个作为开头的波谷(代码中的num0)的数量都是1,波峰(代码中的num1)的数量都是0.

我们定义sum数组保存的是之前走过的数字中所有的某个位置上的数字可以作为波峰和波谷的方案数。
once数组保存的是在当前的循环中,某个位置上的数字可以作为波峰和波谷的情况数,每次循环这个数组都会被刷新。

这样的话我们往下走,如果在b数组中遇到一个数与当当前的a数组中的这个数相等,那么我们就需要即需要考虑让这个数作为波谷的情况数,也需要考虑让这个数作为波峰的情况数,并且他可以和数组a中的组成的波浪相匹配,两则之和就是累加上的方案数。

如果在b数组中遇到一个数比当前的a数组中的那个数大,也就相当于a数组的那个数要作为波谷,我们在考虑的时候,就需要想到它在本次的时候作为波谷的情况,还有他可以嫁接到之前的波峰上从而作为波谷的情况。

如果在b数组中遇到一个数比当前的a数组中的那个数小的话,就要考虑a数组中的这个数作为波峰的情况,其思考方法与前面的类似。

代码:

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
const int max_n=2009;
const int mod=998244353;
int a[max_n],b[max_n];
int n,m,num0,num1,ans;
int once[max_n][2],sum[max_n][2];///once是指以b数组中此次状态下的的第i为作为谷态(0)和峰态(1)的个数
                                 ///sum是指以b数组中之前所有的的第j位作为谷态(0)和峰态(1)的个数
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        ans=0;
        memset(sum,0,sizeof(sum));
        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]);
        for(int i=1;i<=n;i++)
        {
            num0=1;///表示此次作为波谷的个数,因为最开始的那个肯定要从波谷开始
            num1=0;///表示此次作为波峰的个数
            for(int j=1;j<=m;j++)
            {
                if(a[i]==b[j])///两个相同的话,则进行状态的转移
                {
                    once[j][0]=num0;
                    once[j][1]=num1;
                    ans=(ans+(once[j][0]+once[j][1])%mod)%mod;
                }
                if(a[i]>b[j])///这里作为波峰
                {
                    num1=(num1+sum[j][0])%mod;///这次的可以作为波峰的加上之前的波谷
                }
                if(a[i]<b[j])
                {
                    num0=(num0+sum[j][1])%mod;///这次的可以作为波谷的加上之前的波峰
                }
            }
            for(int j=1;j<=m;j++)
            {
                if(a[i]==b[j])
                {
                    sum[j][0]=(sum[j][0]+once[j][0])%mod;
                    sum[j][1]=(sum[j][1]+once[j][1])%mod;
                }
            }
        }
        printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/cmmdc/p/7288934.html