Z2186 I Hate Non-integer Number(线性DP)

目录

题面翻译

样例输入 #1

样例输出 #1

样例输入 #2

样例输出 #2

提示

制約

解题思路


题面翻译

已知一个长度为 𝑁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了,如果有问题,可以告诉我。 

  • 11
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值