mayoko’s diary

プロコンとかいろいろ。

Codeforces Round #309 (Div. 1) A. Kyoya and Colored Balls

Codeforces Round #309 (Div. 1)に参加しました。結果はAB解けて個人的には満足だったんですがレートは多少落ちました(得点dynamic形式は強い人にかなり有利なルールな気がするのでもうちょっと工夫してほしいなぁと思います)。解いてて結構楽しかったのであんまり気にしてないですが。

解法

後ろから考えていきます。例えば問題文の2つ目のサンプルを見てみましょう。
問題の制約から,4が一番後ろに来ることは確定しています。残りの3つの4は好きな場所に配置してよいですが,この配置の仕方はどうなるかというと,1,2,3のボールが6個あって残りの4はこれらのボールの間に入れていくと考えることができるので
{}_{6+1}H_3 = {}_9C_3通りあります。
同様に考えて,次は3のボールを配置することを考えます。3は1,2,3のボールの中で一番最後に一つボールが来ることは確定していて,残りの2つの3のボールの配置の仕方が何通りあるかを考えます。これは1,2のボール3つの中に2つのボールを入れていくと考えることができるので{}_{3+1}H_2 = {}_5C_2通りあります。以下同様です。

何故か制約がゆるいのでO(k^2)でも大丈夫です。

const int MAXN = 1011;
const ll MOD = 1e9+7;
int a[MAXN];
ll fact[MAXN];

// extgcd
ll extgcd(ll a, ll b, ll& x, ll& y) {
    ll d = a;
    if (b != 0) {
        d = extgcd(b, a % b, y, x);
        y -= (a / b) * x;
    } else {
        x = 1; y = 0;
    }
    return d;
}

// mod_inverse
ll mod_inverse(ll a, ll m = MOD) {
    ll x, y;
    extgcd(a, m, x, y);
    return (m+x%m) % m;
}

ll nCr(int n, int r) {
    return (((fact[n] * mod_inverse(fact[r])) % MOD) * mod_inverse(fact[n-r])) % MOD;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    fact[0] = 1;
    for (int i = 1; i < MAXN; i++) {
        fact[i] = fact[i-1] * i;
        fact[i] %= MOD;
    }
    ll ans = 1;
    for (int k = n-1; k > 0; k--) {
        int sum = 0;
        for (int i = 0; i < k; i++) {
            sum += a[i];
        }
        ans *= nCr(sum+a[k]-1, a[k]-1);
        ans %= MOD;
    }
    cout << ans << endl;
    return 0;
}