mayoko’s diary

プロコンとかいろいろ。

SRM 531 div1 easy: NoRepeatPlaylist

解法

包除原理で解きました。

i 個以下の曲を使って P 曲を並べる場合, 最初の曲は i 通り, 次の曲は i-1 通り, ..., M 曲目は i-M 通り, となり, それ以後は i-M 通りだけ使える曲があります。

i 個の曲の選び方は C[N][i] で求められるので, 上の計算でこれを掛け算したものを これを f(i) とすると, N 曲ぴったり使う P 曲の並べ方は, f(N) - f(N-1) + f(N-2) - ... と求められます。

const ll MOD = 1e9+7;
ll C[111][111];

class NoRepeatPlaylist {
public:
    int numPlaylists(int N, int M, int P) {
        if (M > N) return 0;
        if (P < N) return 0;
        for (int i = 0; i < 111; i++) {
            C[i][0] = 1;
            for (int j = 1; j <= i; j++) {
                C[i][j] = C[i-1][j-1] + C[i-1][j];
                C[i][j] %= MOD;
            }
        }
        ll ans = 0;
        for (int i = M; i <= N; i++) {
            ll tmp = 1;
            for (int j = 0; j < P; j++) {
                (tmp *= i-min(j, M)) %= MOD;
            }
            (tmp *= C[N][i]) %= MOD;
            if ((N-i)%2 == 0) ans += tmp;
            else ans -= tmp;
            ans %= MOD;
        }
        (ans += MOD) %= MOD;
        return ans;
    }
};