题目链接:ABC262D
题意:
给出n个正整数,选出若干个数字,求这若干个数字的平均值是正整数的方案数,答案对998244353
取模。
思路:
一开始想着的是dp[i][j][k]
表示前i
个数选择j
个数其中和为k
的方案数。
k
会很大,所以需要考虑取模,存储和对j
取模。
不选a[i]
的转移方程有dp[i][j][k] = dp[i-1][j][k]
,但是如果选a[i]
的时候有些难办,现在sum=k
那上一个状态如何得来?(sum-a[i])%(j-1)=?
这个不好办。所以这个O(n^3)方法不太行。
定义dp[j][k][l]
为把i
作为分母(说明要选i
个数),前j
个数,选择k
个,和模i
为l
的方案数。i
枚举的是子集大小,%i
的意义就是最后要除以的那个i
。
- 不选择
a[j]
:dp[j+1][k][l] += dp[j][k][l];
- 选择
a[j]
:dp[j+1][k+1][(l+a[j])%i] += dp[j][k][l];
需要满足k<i
,因为这是递推的
代码
mint dp[N][N][N],ans;
inline void Case_Test()
{
cin>>n;
for (int i=0;i<n;i++)
cin>>a[i];
for (int i=1;i<=n;i++)
{
memset(dp,0,sizeof dp);
dp[0][0][0] = 1;
for (int j=0;j<n;j++)
for (int k=0;k<=i;k++)
for (int l=0;l<i;l++)
{
dp[j+1][k][l] += dp[j][k][l];
if (k<i) dp[j+1][k+1][(l+a[j])%i] += dp[j][k][l];
}
ans += dp[n][i][0];
}
cout<<ans;
}
文章评论