競技プログラミング日記

主に AtCoder の記事です

AtCoder Beginner Contest 169F問題

ABC169F

和だけが重要なので,\(|U|\) は dp の状態として持っておく必要がない. \(dp_{i,x} := \) \(a_{[0,i)}\) において, \(\emptyset \neq U \subset T \subset N\) となる \(U,T\) のとり方であって, \(sum(a_{U}) = x\) となるものの個数
とする.遷移は,

  • \(a_{i} \in U\) のとき: \(dp_{i+1, x+a_{i}} += dp_{i,x}\) .
  • それ以外のとき: \(a_{i}\) が \(T\) に入るか入らないかの2択であるから, \(dp_{i+1, x} += 2 dp_{i,x}\)

これを inline で高速化すると,

  • \(dp^{\prime}_{i+1, x+a_{i}} += dp^{\prime}_{i,x}\ \),
  • \(dp^{\prime}_{i+1, x} += dp^{\prime}_{i,x}\) .

この時点で \(O(SN)\) であるから十分間に合うが, さらに inline にすると,

  • \(dp^{\prime\prime}_{x+a_{i}} += dp^{\prime\prime}_{x}\ \),
  • \(dp^{\prime\prime}_{x} += dp^{\prime\prime}_{x}\) .

使っている記号,マクロ等 "https://ecsmtlir.hatenablog.com/entry/2022/12/23/131925"

int main() {
  ll n, s ;
  cin >> n >> s;
  vll a(n); rep(i,n) { cin >> a[i]; }

  vector<mint> dp(s+1);
 
  dp[0] = 1;
  rep(i,n){
    // vector<mint> old(s+1);
    // swap(old, dp);
   
    drep(x,s+1){
      ll y = x + a[i];
      // if(y <= s) dp[y] += old[x];
      // dp[x] += mint(2)*old[x];

      if(y <= s) dp[y] += dp[x];
      dp[x] += dp[x];
     
    }
  }

  cout << dp[s].val() << endl;  

  return 0;
}