字数
585 字
阅读时间
3 分钟
原题: 920. 播放列表的数量
题意
有
要求每首歌至少播放一次
求有几种播放顺序
0 <= k < n <= goal <= 100
思路
- 第一步
先只考虑
那么方法数就是
- 第二步
如果间隔
前
第
总数就是
可以表示为
- 第三步
如果每首歌都要播放一次,可以通过
假定最后一首歌我们不使用,那么现在的方法数是
由于歌曲顺序不影响
那么根据容斥原理我们可以很容易得到
答案=总数-没有第一首歌-没2-没3-.... +(没1∩没2)+没1∩没3+.... -(没1∩没2∩没3)-...
也可以写成$$ans=C_n^0 f[n][goal][k]-C_{n}^{1}f[n-1][goal][k]+...$$ 也就是 $$ans=\sum_{i=0}^{n}(-1)^{i}C_{n}^{i}f[n-i][goal][k],i<n-k$$ 公式化简得
代码
CPP
const int N = 110;
const int MOD = 1e9 + 7;
##define vi vector<int>
##define ll long long
ll ksm(ll a, ll b) {
ll ans = 1;
while (b) {
if (b & 1) ans = ans * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return ans;
}
ll inv[N];
ll fa[N];
ll f(int n) {
ll ans = 1;
for (int i = 1; i <= n; i++) ans = ans * i % MOD;
return ans;
}
void lr(int n) {
inv[n] = ksm(f(n), MOD - 2);
for (int i = n - 1; i >= 0; i--) inv[i] = (inv[i + 1] * (i + 1)) % MOD;
fa[1] = 1;
for (int i = 2; i <= n; i++) fa[i] = (fa[i - 1] * i) % MOD;
}
class Solution {
public:
int numMusicPlaylists(int n, int goal, int k) {
lr(100);
ll ans = 0;
ll sta = -1;
for (int i = 0; i < n - k; i++) {
sta = -sta;
ll t = fa[n] * ksm(n - k - i, goal - k) % MOD;
t = t * inv[i] % MOD;
t = t * inv[n - k - i] % MOD;
if (sta == -1) t = t * (MOD - 1) % MOD;
ans = (ans + t) % MOD;
}
return ans;
}
};