Note:暂时只有C和D,后面会更新A,E,F。
题目大意
有多少个整数序列
A
=
(
A
1
,
…
,
A
N
)
A=(A_1,\dots,A_N)
A=(A1?,…,AN?)符合如下条件:
-
1
≤
A
i
≤
M
1\le A_i\le M
1≤Ai?≤M
-
∑
i
=
1
N
A
i
≤
K
\sum\limits_{i=1}^NA_i\le K
i=1∑N?Ai?≤K
输出答案,对
998244353
998244353
998244353取模。
1
≤
N
,
M
≤
50
1\le N,M\le 50
1≤N,M≤50
N
≤
K
≤
N
M
N\le K\le 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
1\le A_x\le M
1≤Ax?≤M),则可得伪代码:
dp[0][0] = 1
for i = 0 to N-1
for j = 0 to K-1
for k = 1 to M
if j + k <= K:
dp[i + 1][j + k] += dp[i][j]
时间复杂度为
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=L∑R?dp(i?1,k), 其中
L
≤
R
L\le 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=\displaystyle\sum_{k=1}^j\mathrm{dp}(i-1,k)
prej?=k=1∑j?dp(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("%d\n", ans);
return 0;
}
题目大意
给定整数序列
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
1≤Ai?,X≤N≤2×105
1
≤
L
≤
R
≤
N
1\le L\le R\le 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("%d\n", int(
lower_bound(pos[x].begin(), pos[x].end(), r) -
lower_bound(pos[x].begin(), pos[x].end(), --l)
));
}
return 0;
}
|