概述
Note:暂时只有C和D,后面会更新A,E,F。
ABC248/UNIQUE2022 C~D
- [C - Dice Sum](https://atcoder.jp/contests/abc248/tasks/abc248_c)
- 题目大意
- 输入格式
- 输出格式
- 分析
- 代码
- [D - Range Count Query](https://atcoder.jp/contests/abc248/tasks/abc248_d)
- 题目大意
- 输入格式
- 输出格式
- 分析
- 代码
C - Dice Sum
题目大意
有多少个整数序列 A = ( A 1 , … , A N ) A=(A_1,dots,A_N) A=(A1,…,AN)符合如下条件:
- 1 ≤ A i ≤ M 1le A_ile M 1≤Ai≤M
- ∑ i = 1 N A i ≤ K sumlimits_{i=1}^NA_ile K i=1∑NAi≤K
输出答案,对 998244353 998244353 998244353取模。
1
≤
N
,
M
≤
50
1le N,Mle 50
1≤N,M≤50
N
≤
K
≤
N
M
Nle Kle NM
N≤K≤NM
输入格式
N M K N~M~K N M K
输出格式
输出答案,对 998244353 998244353 998244353取模。
分析
艹C题又要dp
考虑
DP
text{DP}
DP思想,令
dp
(
i
,
j
)
:
=
A
text{dp}(i,j):=A
dp(i,j):=A的前
i
i
i个元素中和为
j
j
j的总可能数(
1
≤
A
x
≤
M
1le A_xle M
1≤Ax≤M),则可得伪代码:
dp[0][0] = 1
for i = 0 to N-1 // 逐个位置考虑
for j = 0 to K-1 // 考虑所有和的情况,无需考虑K
for k = 1 to M // 1-M的每个选择
if j + k <= K: // 限制条件
dp[i + 1][j + k] += dp[i][j] // 更新dp[i+1]
时间复杂度为 O ( N M K ) mathcal O(NMK) O(NMK),可以通过。
其实还可以利用前缀和优化。
不难发现 d p ( i , j ) = ∑ k = L R dp ( i − 1 , k ) mathrm{dp}(i,j)=displaystylesum_{k=L}^Rtext{dp}(i-1,k) dp(i,j)=k=L∑Rdp(i−1,k),
其中 L ≤ R Lle R L≤R,具体的值请自行推导。
因此,我们可以记录 d p [ i − 1 ] mathrm{dp}[i-1] dp[i−1]的前缀和 p r e mathrm{pre} pre:
- p r e j = ∑ k = 1 j d p ( i − 1 , k ) mathrm{pre}_j=displaystylesum_{k=1}^jmathrm{dp}(i-1,k) prej=k=1∑jdp(i−1,k)
则 d p ( i , j ) = p r e R − p r e L − 1 mathrm{dp}(i,j)=mathrm{pre}_R-mathrm{pre}_{L-1} dp(i,j)=preR−preL−1。
因此,时间复杂度为 O ( N K ) mathcal O(NK) O(NK)。
强烈建议读者独立推导并实现该方法。 前缀和优化 DP text{DP} DP的算法在E、F题中很常见。
代码
#include <cstdio>
#define MOD 998244353
#define maxn 200005
using namespace std;
inline void mod(int& x) { if(x >= MOD) x -= MOD; }
int dp[2][maxn];
int main()
{
int n, m, k;
scanf("%d%d%d", &n, &m, &k);
dp[0][0] = 1;
for(int i=0; i<n; i++)
{
int c = i & 1, p = c ^ 1;
for(int j=0; j<=k; j++)
dp[p][j] = 0;
for(int j=0; j<k; j++)
for(int d=1; d<=m && d<=k-j; d++)
mod(dp[p][j + d] += dp[c][j]);
}
int ans = 0;
for(int i=1; i<=k; i++)
mod(ans += dp[n & 1][i]);
printf("%dn", ans);
return 0;
}
D - Range Count Query
题目大意
给定整数序列
A
=
(
A
1
,
…
,
A
N
)
A=(A_1,dots,A_N)
A=(A1,…,AN)。
有
Q
Q
Q个查询。每个查询的格式如下:
- 给定三个整数 L , R , X L,R,X L,R,X,求 A L , … , A R A_L,dots,A_R AL,…,AR中 X X X的出现次数。
1
≤
A
i
,
X
≤
N
≤
2
×
1
0
5
1le A_i,Xle Nle 2times10^5
1≤Ai,X≤N≤2×105
1
≤
L
≤
R
≤
N
1le Lle Rle N
1≤L≤R≤N
输入格式
N
N
N
A
1
…
A
N
A_1~dots~A_N
A1 … AN
Q
Q
Q
L
1
R
1
X
1
L_1~R_1~X_1
L1 R1 X1
⋮
vdots
⋮
L
Q
R
Q
X
Q
L_Q~R_Q~X_Q
LQ RQ XQ
输出格式
输出 Q Q Q行,第 i i i行是第 i i i个查询的答案。
分析
题目换句话说就是:求
X
X
X出现的位置中,在
[
L
,
R
]
[L,R]
[L,R]区间内的有多少个?
因此,我们很容易想到先预处理
1
,
…
,
N
1,dots,N
1,…,N中每个数出现的位置,存入vector
,查询时二分即可。
代码
注意二分边界。
#include <cstdio>
#include <vector>
#include <algorithm>
#define maxn 200005
using namespace std;
vector<int> pos[maxn];
int main()
{
int n, q;
scanf("%d", &n);
for(int i=0; i<n; i++)
{
int a; scanf("%d", &a);
pos[a].push_back(i);
}
scanf("%d", &q);
while(q--)
{
int l, r, x;
scanf("%d%d%d", &l, &r, &x);
printf("%dn", int(
lower_bound(pos[x].begin(), pos[x].end(), r) -
lower_bound(pos[x].begin(), pos[x].end(), --l)
));
}
return 0;
}
最后
以上就是清新冬日为你收集整理的UNIQUE VISION Programming Contest 2022(AtCoder Beginner Contest 248)C~D 题解C - Dice SumD - Range Count Query的全部内容,希望文章能够帮你解决UNIQUE VISION Programming Contest 2022(AtCoder Beginner Contest 248)C~D 题解C - Dice SumD - Range Count Query所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复