目录
题面翻译
已知一个长度为 𝑁N 的数列 𝑎1,𝑎2,⋯𝑎𝑁a1,a2,⋯aN,从数列中选出至少一个数,使选出的数平均数为整数,求有多少种这样的方案,对 998244353998244353 取模。
样例输入 #1
3
2 6 2
样例输出 #1
6
样例输入 #2
5
5 5 5 5 5
样例输出 #2
31
提示
制約
- 1 ≤ N ≤ 100
- 1 ≤ 𝑎𝑖 ≤ 1091 ≤ ai ≤ 109
解题思路
这道题我们首先要知道什么时候平均数为整数,当N个数的和为ai时,ai mod N == 0,就说明这N个数的平均数是一个整数,这下我们就可以这么想:
定义一个数组dp[i][j][k][q],表示在最多选i个的情况下,前j个,选k个,它们的和mod k余数为q。
思路出来了,于是我兴冲冲地去费劲了九牛二虎之力,终于AK了失败了……
仔细一看,四维数组,开那么大,爆掉了……(此处一阵无语)。那怎么办?我们不妨把数量转换的公式写出来:
1、在不取的情况下用dp[i][j][k][q]去更新dp[i][j+1][k][q]。
2、在取的情况下用dp[i][j][k][q]去更新dp[i][j+1][k+1][(q+a[j])%i]。
代码是这样的
dp[i][j+1][k][q]=(dp[i][j][k][q]+dp[i][j+1][k][q])%mod;
dp[i][j+1][k+1][(q+a[j])%i]=(dp[i][j+1][k+1][(q+a[j])%i]+dp[i][j][k][q])%mod;
这时我想问了,这i是来打酱油的吧?i+1和i之间有什么关系(反正八竿子打不着),所以,我们可以把i去掉,大不了我每次清空数组,改成三维数组,i还是照样循环,这样既可以简化代码,不至于数组BOOM(爆炸),也可以节约空间。
代码是这样的:
dp[j+1][k][q]=(dp[j][k][q]+dp[j+1][k][q])%mod;
dp[j+1][k+1][(q+a[j])%i]=(dp[j+1][k+1][(q+a[j])%i]+dp[j][k][q])%mod;
这下就简洁多了,我们看一下完整代码。
代码实现
#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
long long dp[110][110][110],n,a[110],ans=0;
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
memset(dp,0,sizeof(dp));
dp[1][0][0]=1;
for(int j=1;j<=n;j++){
for(int k=0;k<=i;k++){
for(int q=0;q<=i-1;q++){
dp[j+1][k][q]=(dp[j][k][q]+dp[j+1][k][q])%mod;
dp[j+1][k+1][(q+a[j])%i]=(dp[j+1][k+1][(q+a[j])%i]+dp[j][k][q])%mod;
}
}
}
ans=(ans+dp[n+1][i][0])%mod;
}
cout<<ans<<endl;
return 0;
}
AK了,如果有问题,可以告诉我。