HDU 6078 Wavel Sequence【dp递推】【好题】【思维题】
2017-08-04 23:21
681 查看
4000
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 362 Accepted Submission(s): 175
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(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).
Source
2017 Multi-University Training Contest - Team 4
题意:给出一个有n(<=2000)个数字的序列 a(ai <=2000) 再给出一个有m(m<=2000)个数字的序列 b (bi<=2000) ,定义波浪序列为:x1<x2>x3<x4……(注意第一次必须是上升,不能是下降,也就是说第一项必须是波谷)。现在要求找到一个严格单调递增的序列 f:f1,f2,……fk。以及相对应的严格单调递增的序列g:g1,g2,……gk。(k>=1)使得每个a_fi
= b_gi,同时满足a_f1,a_f2,a_f3……a_fk为波浪序列。求不同的fg映射有多少种选取方式。
a,b中分别从前向后选取k个数字。然后相对应的 a 中选择的每个位置的数字要和 b 中选择的对应位次的数字相同。(当然如果a数组出现过x,而b没有出现过x,显然x不可能被选取),而 f 、g 则是相对应的下标。要满足选取出来的这个数字序列是一个波浪序列。显然波浪序列中的数字分成两种:波峰和波谷。
总体来说,这个题就是a、b数组之间的匹配问题,同时满足是一个波浪序列。
则:
dp[i][j][0]表示以a[i]和b[j]为公共序列结尾且为波谷的情况总和。
dp[i][j][1]则表示波峰的情况总和。
sum[i][j][0]表示sum(dp[k][j][0] | 1<=k<=i-1)
sum[i][j][1]则表示sum(dp[k][j][1] | 1<=k<=i-1) (相当于固定b[j]这个数字,然后将所有可能性加起来)
那么这个过程中只要不断判断这个数字其前面可能的情况(若其为波峰则判断其前可满足作为波谷的数量cnt0,反之亦然),然后判断这个数字能不能加进这个波浪中不断记录结果即可。
注意因为第一次必须为上升,则表示第一个数字前为波峰所以cnt1=1,cnt0=0
这个题有两点值得借鉴:
1、动态规划递推过程中用波峰波谷作为状态转移的关键,然后进行递推
2、用sum来优化其前相加的结果,减少重复的相加运算。
以下是样例的递推过程,蓝色粗线代表程序执行过程,旁边的线代表当前所记录波浪的状态:
可借鉴:点击打开链接的思路
Wavel Sequence
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 362 Accepted Submission(s): 175
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(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).
Source
2017 Multi-University Training Contest - Team 4
题意:给出一个有n(<=2000)个数字的序列 a(ai <=2000) 再给出一个有m(m<=2000)个数字的序列 b (bi<=2000) ,定义波浪序列为:x1<x2>x3<x4……(注意第一次必须是上升,不能是下降,也就是说第一项必须是波谷)。现在要求找到一个严格单调递增的序列 f:f1,f2,……fk。以及相对应的严格单调递增的序列g:g1,g2,……gk。(k>=1)使得每个a_fi
= b_gi,同时满足a_f1,a_f2,a_f3……a_fk为波浪序列。求不同的fg映射有多少种选取方式。
a,b中分别从前向后选取k个数字。然后相对应的 a 中选择的每个位置的数字要和 b 中选择的对应位次的数字相同。(当然如果a数组出现过x,而b没有出现过x,显然x不可能被选取),而 f 、g 则是相对应的下标。要满足选取出来的这个数字序列是一个波浪序列。显然波浪序列中的数字分成两种:波峰和波谷。
总体来说,这个题就是a、b数组之间的匹配问题,同时满足是一个波浪序列。
则:
dp[i][j][0]表示以a[i]和b[j]为公共序列结尾且为波谷的情况总和。
dp[i][j][1]则表示波峰的情况总和。
sum[i][j][0]表示sum(dp[k][j][0] | 1<=k<=i-1)
sum[i][j][1]则表示sum(dp[k][j][1] | 1<=k<=i-1) (相当于固定b[j]这个数字,然后将所有可能性加起来)
那么这个过程中只要不断判断这个数字其前面可能的情况(若其为波峰则判断其前可满足作为波谷的数量cnt0,反之亦然),然后判断这个数字能不能加进这个波浪中不断记录结果即可。
注意因为第一次必须为上升,则表示第一个数字前为波峰所以cnt1=1,cnt0=0
这个题有两点值得借鉴:
1、动态规划递推过程中用波峰波谷作为状态转移的关键,然后进行递推
2、用sum来优化其前相加的结果,减少重复的相加运算。
以下是样例的递推过程,蓝色粗线代表程序执行过程,旁边的线代表当前所记录波浪的状态:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <string> #include <map> #include <cstring> #define INF 0x3f3f3f3f #define ms(x,y) memset(x,y,sizeof(x)) using namespace std; typedef long long ll; typedef pair<int, int> P; const int maxn = 2e3 + 10; const int mod = 998244353; int n, m; int a[maxn], b[maxn]; ll dp[maxn][2]; //原为dp[i][j][2] 表示a数组枚举到第i个,b数组枚举到第j个,dp[i][j][0]表示当前选的数为波谷,反之同理,因为只用到上一个i-1所以利用滚动数组将其省去 ll sum[maxn][2]; //原为sum[i][j][2]表示a数组枚举从1到第i个,b数组枚举到第j个波峰(sum[i][j][1])或波谷(sum[i][j][0])的和 int main() { int t; scanf("%d", &t); while (t--) { ll ans = 0; scanf("%d%d", &n, &m); ms(sum, 0); ms(dp, 0); 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]作为谷底的所有可能加进去,方便下次统计,减少重复计算(dp的递推优化) sum[j][1] = (sum[j][1] + dp[j][1]) % mod; //同理 } } } printf("%lld\n", ans); } return 0; }
可借鉴:点击打开链接的思路
相关文章推荐
- HDU 4689 Derangement【DP递推】【好题】【思维题】
- HDU 6078 Wavel Sequence 树状数组优化DP
- hdu 6078 Wavel Sequence(前缀和优化dp)
- 2017多校训练赛第四场 HDU 6078 Wavel Sequence(dp+优化)
- HDU 6078 Wavel Sequence(dp)
- HDU_6078 Wavel Sequence 【DP】
- HDU 6078 Wavel Sequence (dp)
- hdu--6078--Wavel Sequence(dp)
- 多校4 HDU-6078 Wavel Sequence 前缀和 & 优化dp
- HDU 6143 Killer Names【dp递推】【好题】【思维题】【阅读题】
- HDU 6078 Wavel Sequence【DP+优化】
- HDU - 2050 折线分割平面 (思维+dp)
- hdu 4472 Count【思维+dp】好题
- Hdu 6212 Zuma【思维+区间Dp】
- 2016多校第4场 HDU 6076 Security Check DP,思维
- hdu1978(递推dp)
- HDU 2709 Sumsets(DP递推)
- HDU 数塔DP思维设计
- [递推简单dp]-hdu 2084 数塔
- HDU 6172 and HDU 6185 【线性递推 + 思维 + 板子】