競プロ記録

問題を解いた際に自分の復習用として使ってます

yukicoder No.129

解説

基本的な解法の方針は動的計画法です。
そしてお金は1000円単位で平等に配るので、n/1000 mod m 円を分配することは容易にわかると思います。
なので k = n/1000 mod m とすると求めるのはm人にk枚を平等に配るので一人あたり1000円になります。よって総数は mCk です。

ここでmCkを動的計画法を用いて求めます。そこで必要となるのがパスカルの三角形です。

パスカルの三角形は聞いたことがあると思うので省略します。動的計画法を用いやすいように左側に寄せて記述すると以下のようになります。

1
1 1
1 2 1
1 3 3 1
1 4 9 4 1
1 5 13 13 5 1
….

よって次の式が成立します。

dp[i][j] = dp[i-1][j-1] + dp[i-1][j]

これは比較的簡単に導出できるかと思います。しかしこれですとmか104までなのでメモリが足りません。
なのでi番目の段の値だけを保持して、i+1番目の段の値を計算し、、、を繰り返していけば求めれます。

コード

#include <iostream>
using namespace std;

const int mod = 1e9;
int main(void){
    long long n,m;
    cin >> n >> m;
    long long k = (n/1000)%m;
    long long before[10003], after[10003];
    before[0] = 1;
    if(k != 0){
        for(int i=1; i<=m; i++){
            for(int j=1; j<=i; j++){
                after[j] = (before[j-1]+before[j])%mod;
            }
            before[0] = 1;
            for(int j=1; j<=i; j++){
                before[j] = after[j];
            }
        }
    }
    cout << (before[k]%mod) << endl;
    return 0;
}