一看期望就害怕.

首先这个操作只能影响到比自己小的位置, 考虑一个最大的位置, 那么当前要翻就必须翻, 我们从大到小查一遍, 就知道要按几个灯了. 这个时候按灯的顺序就不重要了, 我们可以抽象成需要按$i$个灯的期望步数.

直接算会GG, 我们将期望差分为按$i$个灯转移到按$i-1$个灯的期望步数, 那么有转移:

$E_i = \frac{i}{n} + (1-\frac{i}{n})(E_i + E_{i+1}+1)$. 前一部分是按对了, 后一部分是没按对, 这样就多了一个需要按的, 还需要按回来.

可以递推. 然后对于小于$k$的时候就不推了, 直接算答案.

最后把答案乘上$N!$.

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
#include <bits/stdc++.h>
#define mod 100003

using namespace std;
typedef long long ll;

const int maxn = 100005;

int n, k, a[maxn], cor;
ll E[maxn], inv[maxn];
vector<int> vec[maxn];

int main() {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; ++i) {
for (int j = i; j <= n; j += i)
vec[j].push_back(i);
}
for (int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
inv[1] = 1;
for (int i = 2; i <= n; ++i)
inv[i] = inv[mod % i] * (mod - mod / i) % mod;
for (int i = n; i > k; --i) {
E[i] = (n + (n - i) * E[i + 1] % mod) % mod * inv[i] % mod;
}
for (int i = k; i; --i) E[i] = 1;
for (int i = n; i; --i) {
if (a[i]) {
for (int j = 0; j < (int)vec[i].size(); ++j)
a[vec[i][j]] ^= 1;
cor++;
}
}
ll ans = 0;
for (int i = 1; i <= cor; ++i)
ans = (ans + E[i]) % mod;
for (int i = 1; i <= n; ++i)
ans = (ans * i) % mod;
printf("%lld\n", ans);
return 0;
}