👋
ABC262 D - I Hate Non-integer Number
問題概要
問題文
長さ
の正整数列 N が与えられる。 A=(A_1,A_2,\dots,A_N)
から A 個以上の要素を選ぶとき、選んだ要素すべての平均値が整数となるようなものはいくつあるか? 1
制約
1\leq N\leq 100 1\leq A_i\leq 10^9 - 入力はすべて整数
問題リンク
考えたこと
ある程度
平均値と書いてあるが、要は「選んだ要素の総和」が「選んだ要素の個数」の倍数であればよい。
これは部分和問題の進化系みたいな感じなので、DPとかを使えばよさそう。
次のようなことを考えた。
dp[i][j][k]=Aの先頭i項からj個選ぶとき、選んだ要素の和をjで割った余りがkであるような個数
ただ、これだと「j
で割った余り」がj
が動くときに扱いづらい。
じゃあ、あらかじめ選ぶ個数siz
を固定してしまえばよい。
こうすると、siz=1,2,...,N
について、順に
「総和がsiz
の倍数となるようにsiz
個の要素を選ぶ方法」
を求めて総和を出せばよい。これらは、次のようなDPで解決できる。
dp[i][j][k]=Aの先頭i項からj個選ぶとき、選んだ要素の和をsizで割った余りがkとなるような個数
これなら遷移が簡単。
siz=1,...,n
に対してdp[n][siz][0]
を求めて、それらの総和を求めればよい。
dpは状態数がsiz
に対してdp
は
さらに、siz
が
実装
#include<iostream>
#include<vector>
using namespace std;
int main() {
const int mod=998244353;
//入力
int n;
cin>>n;
vector<int> a(n);
for(auto&aa:a)cin>>aa;
int ans=0;
//siz=1,2,...,nで動かす
for(int siz=1;siz<=n;siz++){
//dp[i][j][k]:=先頭i項からj項選ぶ。選んだ要素の和をsizで割った余りがkとなるような個数。
vector<vector<vector<int>>> dp(n+1,vector<vector<int>>(siz+1,vector<int>(siz)));
dp[0][0][0]=1;
for(int i=0;i<n;i++)for(int j=0;j<=siz;j++)for(int k=0;k<siz;k++){
//a[i]を選ばないとき
dp[i+1][j][k]+=dp[i][j][k];
dp[i+1][j][k]%=mod;
//a[i]を選ぶとき
if(j+1<=siz){
dp[i+1][j+1][(k+a[i])%siz]+=dp[i][j][k];
dp[i+1][j+1][(k+a[i])%siz]%=mod;
}
}
ans+=dp[n][siz][0];
ans%=mod;
}
//出力
cout<<ans<<endl;
}
Discussion