競技プログラミング日記

主に AtCoder の記事です

AtCoder Beginner Contest 216F

ABC216F

\(max(A_{S})\) と \(sum(B_{S})\) をとる. \(A\) をソートしておくと良さそう,ただしそれに合わせて \(B\) も一緒にソートする. \(i \in N\) を全探索して, \(A_{i}\) が最大になる \(S\) の取り方を調べる. \(sum(B_{S}) \leq A_{i}\) になる様にすればよい. よって,以下のDPが良い.
\(dp[i][x] := [0,i)\) で見たときの, \(B\) の部分和で \(x\) 以下になるものの個数.
これは部分和DPとほぼ同じで,初期化が異なるだけ. \(dp[0][x] = 1\) , \(x \geq 0\) とすれば良い. 初期値 \(0\) から 和\(t\) を作るのと, 初期値 \(S-t\) から 和\(S\) を作るのは対応するから. ここで, \(0 \leq t \leq S\).

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

int main() {
  ll n;
  cin >> n;
  vector<pll> p(n);
  rep(i,n){
    cin >> p[i].first;
  }
  rep(i,n){
    cin >> p[i].second;
  }
  sort(all(p));

  const ll ma = 5000;
  mint ans = 0;
  vector<mint> dp(ma+1, 1);
  rep(i,n){
    auto [a,b] = p[i];

    // dp: [0,i)
    if(a >= b) ans += dp[a-b];

    // ------------------------
    drep(x,ma+1){
      ll y = b + x;
      if(y <= ma) dp[y] += dp[x];
    }
    // dp: [0,i]

  }
  cout << ans.val() << endl;
 

  return 0;
}