2021-2022-1 ACM集训队每周程序设计竞赛 - 问题 E: 数学!- 题解
Posted Tisfy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021-2022-1 ACM集训队每周程序设计竞赛 - 问题 E: 数学!- 题解相关的知识,希望对你有一定的参考价值。
数学!
时间限制:1秒
空间限制:128M
题目描述
给你两个长度分别为 n n n和 m m m的数组 S S S、 T T T,问你 S S S的子序列有多少和 T T T的子序列相同。
此题子序列不要求连续,即:从序列 a a a中删除 0 0 0到 l e n ( a ) len(a) len(a)个元素后得到的序列即为 a a a的子序列。
输入描述
第一行空格隔开的两个正整数 n n n和 m m m,分别代表序列 S S S的长度和序列 T T T的长度。
第二行 n n n个空格隔开的正整数,代表序列 S S S。
第三行 m m m个空格隔开的正整数,代表序列 T T T。
输入格式如下:
n m
S1 S2 ... S3
T1 T2 ... T3s
其中:
- 1 ≤ n , m ≤ 2 × 1 0 3 1\\leq n,m\\leq2\\times10^3 1≤n,m≤2×103
- 1 ≤ S i , T i ≤ 1 0 5 1\\leq S_i, T_i\\leq 10^5 1≤Si,Ti≤105
- 所有输入的数都为正整数
输出描述
输出一行一个正整数代表序列 S S S和序列 T T T的相同子序列的个数,答案对 1 0 9 + 7 10^9+7 109+7取模。
样例一
输入
2 2
1 3
3 1
输出
3
样例二
输入
2 2
1 1
1 1
输出
6
提示
样例一中,
序列
S
S
S有
4
4
4个子序列:
(
)
,
(
1
)
,
(
3
)
,
(
1
,
3
)
(),(1),(3),(1,3)
(),(1),(3),(1,3)
序列
T
T
T有
4
4
4个子序列:
(
)
,
(
3
)
,
(
1
)
,
(
3
,
1
)
(),(3),(1),(3,1)
(),(3),(1),(3,1)
相同子序列有 3 3 3对: ( ) , ( 1 ) , ( 3 ) (),(1),(3) (),(1),(3)
题目分析
这道题可以使用动态规划。
用数组
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 表示序列
S
S
S的前
i
i
i个数 及 序列
T
T
T的前
j
j
j个数 的相同子序列的个数(即问题所问)
那么因为可以有空的子序列,所以
d
p
[
∗
]
[
0
]
dp[*][0]
dp[∗][0]都等于
1
1
1,
d
p
[
0
]
[
∗
]
dp[0][*]
dp[0][∗]也都等于
1
1
1(一个一定长度的序列和一个空序列的相同子序列为空的序列)
-
当 S [ i ] ≠ T [ j ] S[i]\\neq T[j] S[i]=T[j]时,有转移方程: d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] − d p [ i − 1 ] [ j − 1 ] dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1] dp[i][j]=dp[i−1][j]+dp[i][j−1]−dp[i−1][j−1],即为 S S S的前 i − 1 i-1 i−1个元素和 T T T的前 j j j个元素的相同子序列数+ S S S的前 i i i个元素和 T T T的前 j − 1 j-1 j−1个元素的相同子序列数。
但是 S S S的前 i i i个元素和 T T T的前 j j j个元素计算了两次,根据容斥原理,我们需要再减去 S S S的前 i i i个元素和 T T T的前 j j j个元素的相同子序列的个数。 -
当 S [ i ] = T [ j ] S[i]= T[j] S[i]=T[j]时,序列 S S S的前 i − 1 i-1 i−1个元素和序列 T T T的前 j − 1 j-1 j−1个元素的任意一个公共子序列同时加上 S [ i ] S[i] S[i]得到的新的序列也相同。此时转移方程为 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] − d p [ i − 1 ] [ j − 1 ] + d p [ i − 1 ] [ j − 1 ] = d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+dp[i-1][j-1]=dp[i-1][j]+dp[i][j-1] dp[i][j]=dp[i−1][j]+dp[i][j−1]−dp[i−1][j−1]+dp[i−1][j−1]=dp[i−1][j]+dp[i][j−1]
综上,我们有转移方程 d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] dp[i][j]=dp[i-1][j]+dp[i][j-1] dp[i][j]=dp[i−1][j]+dp[i][j−1],而当 S [ i ] ≠ T [ j ] S[i]\\neq T[j] S[i]=T[j]时,需要减去一个 d p [ i − 1 ] [ j − 1 ] dp[i-1][j-1] dp[i−1][j−1]。
AC代码
#include <bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define dbg(x) cout << #x << " = " << x << endl
#define fi(i, l, r) for (int i = l; i <= r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
const ll mod = 1e9 + 7;
ll dp[2010][2010] = {1};
int a[2010], b[2010];以上是关于2021-2022-1 ACM集训队每周程序设计竞赛 - 问题 E: 数学!- 题解的主要内容,如果未能解决你的问题,请参考以下文章
BUCT - 2021-2022-1 ACM集训队每周程序设计竞赛(10)题解
BUCT - 2021-2022-1 ACM集训队每周程序设计竞赛题解
BUCT - 2021-2022-1 ACM集训队每周程序设计竞赛题解