AtCoder Beginner Contest 262
D - I Hate Non-integer Number
题意
给你一个长度为 n n n的数组,问:从数组中选择任意个 元素,这些元素的平均数为整数的方案数为多少。
数据范围
1
⩽
n
⩽
100
1 \leqslant n \leqslant 100
1⩽n⩽100
思路
本题考察 动态规划
我们令
d
p
[
j
]
[
k
]
[
l
]
dp[j][k][l]
dp[j][k][l]为在长度为
i
i
i的情况下,数组中前
j
j
j个元素中选择
k
k
k个元素
m
o
d
mod
mod
%
i
\%i
%i 为
l
l
l的方案数。
那么答案就是
∑
i
=
1
n
d
p
[
n
]
[
i
]
[
0
]
\sum_{i = 1}^{n} dp[n][i][0]
i=1∑ndp[n][i][0]
转移:我们可以考虑第
j
j
j个数是否选择来进行转移
d
p
[
j
]
[
k
]
[
l
]
=
{
d
p
[
j
−
1
]
[
k
]
[
l
]
(
不选
)
d
p
[
j
−
1
]
[
k
−
1
]
[
l
−
(
a
[
j
]
%
i
)
]
(
a
[
j
]
%
i
⩾
0
)
d
p
[
j
−
1
]
[
k
−
1
]
[
i
+
l
−
(
a
[
j
]
%
i
)
]
(
a
[
j
]
%
i
<
0
)
dp[j][k][l] = \begin{cases}dp[j - 1][k][l]\quad(不选)\\ dp[j - 1][k - 1][l - (a[j]\ \% \ i)] \quad(a[j] \ \%\ i\ \geqslant\ 0)\\ dp[j - 1][k - 1][i + l - (a[j] \ \% \ i)]\quad (a[j]\ \% \ i< 0)\end{cases}
dp[j][k][l]=⎩
⎨
⎧dp[j−1][k][l](不选)dp[j−1][k−1][l−(a[j] % i)](a[j] % i ⩾ 0)dp[j−1][k−1][i+l−(a[j] % i)](a[j] % i<0)
初始化:
d
p
[
0
]
[
0
]
[
0
]
=
1
dp[0][0][0] = 1
dp[0][0][0]=1
时间复杂度
O ( N 4 ) O(N^4) O(N4)
代码
#include <bits/stdc++.h>
#define PII pair<int,int>
#define LL long long
#define fi first
#define se second
#define debug(a) cout<<#a<<"="<<a<<endl;
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define Yes puts("Yes");
#define No puts("No");
#define sz(x) (int)x.size()
using namespace std;
inline string rd()
{
string str="";
char ch=getchar();
while(ch==' ' || ch=='\n' || ch=='\r')
{
ch=getchar();
}
while(ch!=' ' && ch!='\n' && ch!='\r')
{
str+=ch;
ch=getchar();
}
return str;
}
inline void print(string s)
{
for(int i=0; s[i]!='\0'; i++) putchar(s[i]);
}
template <typename T> void read(T &t) {
t=0; char ch=getchar(); int f=1;
while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
do { (t*=10)+=ch-'0'; ch=getchar(); } while ('0'<=ch&&ch<='9'); t*=f;
}
template <typename T> void write(T t) {
if (t<0) { putchar('-'); write(-t); return; }
if (t>9) write(t/10);
putchar('0'+t%10);
}
template <typename T> void writeln(T t) { write(t); puts(""); }
const int N = 110, mod = 998244353;
int a[N], n;
LL dp[N][N][N];//dp[j][k][l]表示前j个数选则k个数的和modi为l的方案数
int main()
{
read(n);
LL sum = 0;
for(int i = 1; i <= n; i ++ ) read(a[i]);
for(int i = 1; i <= n; i ++ ){//一共选i个数 O(N^4)
dp[0][0][0] = 1;
for(int j = 1; j <= n; j ++ ){
for(int k = 0; k <= j; k ++ ){
for(int l = 0; l < i; l ++ ){
// 不选的方案数
dp[j][k][l] = (dp[j][k][l] + dp[j - 1][k][l]) % mod;
// 选的方案数
int x = a[j] % i;
if(k >= 1){
if(l - x >= 0) dp[j][k][l] = (dp[j][k][l] + dp[j - 1][k - 1][l - x]) % mod;
else dp[j][k][l] = (dp[j][k][l] + dp[j - 1][k - 1][i + l - x]) % mod;
}
}
}
}
sum += dp[n][i][0];
sum %= mod;
memset(dp, 0, sizeof dp);
}
printf("%lld\n",sum);
return 0;
}