我是靠谱客的博主 清新冬日,最近开发中收集的这篇文章主要介绍UNIQUE VISION Programming Contest 2022(AtCoder Beginner Contest 248)C~D 题解C - Dice SumD - Range Count Query,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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 1AiM
  • ∑ i = 1 N A i ≤ K sumlimits_{i=1}^NA_ile K i=1NAiK

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

1 ≤ N , M ≤ 50 1le N,Mle 50 1N,M50
N ≤ K ≤ N M Nle Kle 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 1le A_xle 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)=displaystylesum_{k=L}^Rtext{dp}(i-1,k) dp(i,j)=k=LRdp(i1,k)
其中 L ≤ R Lle 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=displaystylesum_{k=1}^jmathrm{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("%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 1Ai,XN2×105
1 ≤ L ≤ R ≤ N 1le Lle Rle 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("%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所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(34)

评论列表共有 0 条评论

立即
投稿
返回
顶部