UNIQUE VISION Programming Contest 2022(AtCoder Beginner Contest 248)C~D 题解

46 篇文章 7 订阅
43 篇文章 5 订阅

Note:暂时只有C和D,后面会更新A,E,F。

C - Dice Sum

题目大意

有多少个整数序列 A = ( A 1 , … , A N ) A=(A_1,\dots,A_N) A=(A1,,AN)符合如下条件:

  • 1 ≤ A i ≤ M 1\le A_i\le M 1AiM
  • ∑ i = 1 N A i ≤ K \sum\limits_{i=1}^NA_i\le K i=1NAiK

输出答案,对 998244353 998244353 998244353取模。

1 ≤ N , M ≤ 50 1\le N,M\le 50 1N,M50
N ≤ K ≤ N M N\le K\le NM NKNM

输入格式

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 1\le A_x\le M 1AxM),则可得伪代码:

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)=\displaystyle\sum_{k=L}^R\text{dp}(i-1,k) dp(i,j)=k=LRdp(i1,k)
其中 L ≤ R L\le R LR,具体的值请自行推导。
因此,我们可以记录 d p [ i − 1 ] \mathrm{dp}[i-1] dp[i1]的前缀和 p r e \mathrm{pre} pre

  • p r e j = ∑ k = 1 j d p ( i − 1 , k ) \mathrm{pre}_j=\displaystyle\sum_{k=1}^j\mathrm{dp}(i-1,k) prej=k=1jdp(i1,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)=preRpreL1
因此,时间复杂度为 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("%d\n", 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 1\le A_i,X\le N\le 2\times10^5 1Ai,XN2×105
1 ≤ L ≤ R ≤ N 1\le L\le R\le N 1LRN

输入格式

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("%d\n", int(
			lower_bound(pos[x].begin(), pos[x].end(), r) -
			lower_bound(pos[x].begin(), pos[x].end(), --l)
		));
	}
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AtCoder Beginner Contest 134 是一场 AtCoder 的入门级比赛,以下是每道题的简要题解: A - Dodecagon 题目描述:已知一个正十二边形的边长,求它的面积。 解题思路:正十二边形的内角为 $150^\circ$,因此可以将正十二边形拆分为 12 个等腰三角形,通过三角形面积公式计算面积即可。 B - Golden Apple 题目描述:有 $N$ 个苹果和 $D$ 个盘子,每个盘子最多可以装下 $2D+1$ 个苹果,求最少需要多少个盘子才能装下所有的苹果。 解题思路:每个盘子最多可以装下 $2D+1$ 个苹果,因此可以将苹果平均分配到每个盘子中,可以得到最少需要 $\lceil \frac{N}{2D+1} \rceil$ 个盘子。 C - Exception Handling 题目描述:给定一个长度为 $N$ 的整数序列 $a$,求除了第 $i$ 个数以外的最大值。 解题思路:可以使用两个变量 $m_1$ 和 $m_2$ 分别记录最大值和次大值。遍历整个序列,当当前数不是第 $i$ 个数时,更新最大值和次大值。因此,最后的结果应该是 $m_1$ 或 $m_2$ 中较小的一个。 D - Preparing Boxes 题目描述:有 $N$ 个盒子和 $M$ 个物品,第 $i$ 个盒子可以放入 $a_i$ 个物品,每个物品只能放在一个盒子中。现在需要将所有的物品放入盒子中,每次操作可以将一个盒子内的物品全部取出并分配到其他盒子中,求最少需要多少次操作才能完成任务。 解题思路:首先可以计算出所有盒子中物品的总数 $S$,然后判断是否存在一个盒子的物品数量大于 $\lceil \frac{S}{2} \rceil$,如果存在,则无法完成任务。否则,可以用贪心的思想,每次从物品数量最多的盒子中取出一个物品,放入物品数量最少的盒子中。因为每次操作都会使得物品数量最多的盒子的物品数量减少,而物品数量最少的盒子的物品数量不变或增加,因此这种贪心策略可以保证最少需要的操作次数最小。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值