题目链接
题意
给一个序列,让你计算有多少序列$b$满足:
1.每个位置。
2.。
3.和原来数列恰好有$k$个位置数字不同。
思路
思路不难想,计算出$F(d)$,然后去暴力计算每一个$f(d)$。
其中$c$为数字$d$的倍数出现的次数。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
using namespace std;
typedef long long ll;
void err(){cout << "\033[39;0m" << endl;}
template<template<typename...> class T, typename t, typename... A>
void err(T<t> a, A... x){for (auto v: a) cout << v << ' '; err(x...);}
template<typename T, typename... A>
void err(T a, A... x){cout << a << ' '; err(x...);}
const int N = 3e5 + 5;
int a[N];
int prime[N];
int tot, vis[N];
int miu[N];
ll F[N];
void pre(int n)
{
miu[1] = 1;
tot = 0;
for (int i = 2; i <= n; i++)
{
if (!vis[i])
{
prime[++tot] = i;
miu[i] = -1;
}
for (int j = 1; j <= tot && i * prime[j] <= n; j++)
{
vis[i * prime[j]] = 1;
if (i % prime[j] == 0)
{
miu[i * prime[j]] = 0;
break;
}
miu[i * prime[j]] = -miu[i];
}
}
}
int cnt[N];
const ll mod = 1e9 + 7;
ll Pow(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 fac[N];
ll C(int n, int m)
{
return fac[n] * Pow(fac[n - m] * fac[m] % mod, mod - 2) % mod;
}
int main()
{
fac[0] = 1;
for (int i = 1; i <= 300000; i++)
fac[i] = fac[i - 1] * 1ll * i % mod;
pre(300000);
int n, m, k;
while (~scanf("%d%d%d", &n, &m, &k))
{
memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
cnt[a[i]]++;
}
for (int i = 1; i <= m; i++)
{
ll c = 0;
for (ll d = i; d <= m; d += i)
{
c += cnt[d];
}
if (n - c > k)
F[i] = 0;
else
F[i] = C(c, k - n + c) * Pow(m / i - 1ll, k - n + c) % mod * Pow(m / i, n - c) % mod;
//dbg(i, F[i], k, n, c);
}
for (int i = 1; i <= m; i++)
{
ll ans = 0;
for (ll d = i; d <= m; d += i)
ans = (ans + miu[d / i] * F[d] % mod + mod) % mod;
printf("%lld%c", ans, i == m? '\n': ' ');
}
}
return 0;
}
这里提供另一种思路计算某个数字的倍数的出现次数的方法,用莫比乌斯函数容斥一下。
但让我百思不得其解的是这种方法竟然比上面要慢。
如果有人可以帮我证明这两种方法的优劣性,欢迎联系我。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
using namespace std;
typedef long long ll;
void err(){cout << "\033[39;0m" << endl;}
template<template<typename...> class T, typename t, typename... A>
void err(T<t> a, A... x){for (auto v: a) cout << v << ' '; err(x...);}
template<typename T, typename... A>
void err(T a, A... x){cout << a << ' '; err(x...);}
const int N = 3e5 + 5;
int a[N];
int prime[N];
int tot, vis[N];
int miu[N];
ll F[N];
void pre(int n)
{
miu[1] = 1;
tot = 0;
for (int i = 2; i <= n; i++)
{
if (!vis[i])
{
prime[++tot] = i;
miu[i] = -1;
}
for (int j = 1; j <= tot && i * prime[j] <= n; j++)
{
vis[i * prime[j]] = 1;
if (i % prime[j] == 0)
{
miu[i * prime[j]] = 0;
break;
}
miu[i * prime[j]] = -miu[i];
}
}
}
int cnt[N];
const ll mod = 1e9 + 7;
ll Pow(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 fac[N];
ll dfs(int p, int m)
{
if (vis[p])
return cnt[p];
for (int i = 2; p * i <= m; i++)
if (miu[i])
cnt[p] = (cnt[p] - miu[i] * dfs(p * i, m) % mod + mod) % mod;
vis[p] = 1;
//dbg(p, cnt[p]);
return cnt[p];
}
ll C(int n, int m)
{
return fac[n] * Pow(fac[n - m] * fac[m] % mod, mod - 2) % mod;
}
int main()
{
fac[0] = 1;
for (int i = 1; i <= 300000; i++)
fac[i] = fac[i - 1] * 1ll * i % mod;
pre(300000);
int n, m, k;
while (~scanf("%d%d%d", &n, &m, &k))
{
memset(cnt, 0, sizeof(cnt));
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
cnt[a[i]]++;
}
for (int i = 1; i <= m; i++)
vis[i] = 0;
dfs(1, m);
for (int i = 1; i <= m; i++)
{
/*
ll c = 0;
for (ll d = i; d <= m; d += i)
{
c += cnt[d];
}
*/
ll c = cnt[i];
if (n - c > k)
F[i] = 0;
else
F[i] = C(c, k - n + c) * Pow(m / i - 1ll, k - n + c) % mod * Pow(m / i, n - c) % mod;
//dbg(i, F[i], k, n, c);
}
for (int i = 1; i <= m; i++)
{
ll ans = 0;
for (ll d = i; d <= m; d += i)
ans = (ans + miu[d / i] * F[d] % mod + mod) % mod;
printf("%lld%c", ans, i == m? '\n': ' ');
}
}
return 0;
}