GoodCoder666的个人博客

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

2022-04-17 · 5 min read
C++ 算法竞赛

C - Dice Sum

题目大意

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

  • 1AiM1\le A_i\le M
  • i=1NAiK\sum\limits_{i=1}^NA_i\le K

输出答案,对998244353998244353取模。

1N,M501\le N,M\le 50
NKNMN\le K\le NM

输入格式

N M KN~M~K

输出格式

输出答案,对998244353998244353取模。

分析

艹C题又要dp
考虑DP\text{DP}思想,令dp(i,j):=A\text{dp}(i,j):=A的前ii个元素中和为jj的总可能数(1AxM1\le A_x\le 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(NMK)\mathcal O(NMK),可以通过

其实还可以利用前缀和优化
不难发现dp(i,j)=k=LRdp(i1,k)\mathrm{dp}(i,j)=\displaystyle\sum_{k=L}^R\text{dp}(i-1,k)
其中LRL\le R,具体的值请自行推导。
因此,我们可以记录dp[i1]\mathrm{dp}[i-1]的前缀和pre\mathrm{pre}

  • prej=k=1jdp(i1,k)\mathrm{pre}_j=\displaystyle\sum_{k=1}^j\mathrm{dp}(i-1,k)

dp(i,j)=preRpreL1\mathrm{dp}(i,j)=\mathrm{pre}_R-\mathrm{pre}_{L-1}
因此,时间复杂度为O(NK)\mathcal O(NK)
强烈建议读者独立推导并实现该方法。 前缀和优化DP\text{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=(A1,,AN)A=(A_1,\dots,A_N)
QQ个查询。每个查询的格式如下:

  • 给定三个整数L,R,XL,R,X,求AL,,ARA_L,\dots,A_RXX的出现次数。

1Ai,XN2×1051\le A_i,X\le N\le 2\times10^5
1LRN1\le L\le R\le N

输入格式

NN
A1  ANA_1~\dots~A_N
QQ
L1 R1 X1L_1~R_1~X_1
\vdots
LQ RQ XQL_Q~R_Q~X_Q

输出格式

输出QQ行,第ii行是第ii个查询的答案。

分析

题目换句话说就是:求XX出现的位置中,在[L,R][L,R]区间内的有多少个?
因此,我们很容易想到先预处理1,,N1,\dots,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;
}