You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

73 lines
2.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class_2023_02_2_week;
// 你的音乐播放器里有 N 首不同的歌
// 在旅途中,你的旅伴想要听 L 首歌(不一定不同,即,允许歌曲重复
// 请你为她按如下规则创建一个播放列表
// 每首歌至少播放一次
// 一首歌只有在其他 K 首歌播放完之后才能再次播放
// 返回可以满足要求的播放列表的数量
// 由于答案可能非常大,请返回它模 10^9 + 7 的结果
// 测试链接 : https://leetcode.cn/problems/number-of-music-playlists/
public class Code01_NumberOfMusicPlaylists {
public static int mod = 1000000007;
public static int limit = 100;
// 阶乘表
public static long[] fac = new long[limit + 1];
// 阶乘结果的乘法逆元表
public static long[] inv = new long[limit + 1];
static {
fac[0] = inv[0] = 1;
for (int i = 1; i <= limit; i++) {
fac[i] = ((long) i * fac[i - 1]) % mod;
}
// 费马小定理计算乘法逆元
// for (int i = 1; i <= limit; i++) {
// inv[i] = power(fac[i], mod - 2);
// }
// 费马小定理计算乘法逆元,优化如下
// 这一块叫:阶乘的逆元倒推
inv[limit] = power(fac[limit], mod - 2);
for (int i = limit; i > 1; i--) {
inv[i - 1] = ((long) i * inv[i]) % mod;
}
}
// x的n次方% mod之后是多少
public static long power(long x, int n) {
long ans = 1;
while (n > 0) {
if ((n & 1) == 1) {
ans = (ans * x) % mod;
}
x = (x * x) % mod;
n >>= 1;
}
return ans;
}
// n * logn
public static int numMusicPlaylists(int n, int l, int k) {
long cur, ans = 0, sign = 1;
for (int i = 0; i <= n - k; i++, sign = sign == 1 ? (mod - 1) : 1) {
// cur ->
// fac[n] -> n! % mod 的结果!
// inv[i] -> i! 的逆元!
// inv[n - k - i] -> (n - k - i)! 的逆元
// sign * 1 -> 1
// * -1 -> mod - 1
cur = (sign * power(n - k - i, l - k)) % mod;
cur = (cur * fac[n]) % mod;
cur = (cur * inv[i]) % mod;
cur = (cur * inv[n - k - i]) % mod;
ans = (ans + cur) % mod;
}
return (int) ans;
}
}