Description
Zeit und Raum trennen dich und mich.
時空將你我分開。B 君在玩一個遊戲,這個遊戲由 n 個燈和 n 個開關組成,給定這 n 個燈的初始狀態,下標爲
從 1 到 n 的正整數。每個燈有兩個狀態亮和滅,我們用 1 來表示這個燈是亮的,用 0 表示這個燈是滅的,遊戲
的目標是使所有燈都滅掉。但是當操作第 i 個開關時,所有編號爲 i 的約數(包括 1 和 i)的燈的狀態都會被
改變,即從亮變成滅,或者是從滅變成亮。B 君發現這個遊戲很難,於是想到了這樣的一個策略,每次等概率隨機
操作一個開關,直到所有燈都滅掉。這個策略需要的操作次數很多, B 君想到這樣的一個優化。如果當前局面,
可以通過操作小於等於 k 個開關使所有燈都滅掉,那麼他將不再隨機,直接選擇操作次數最小的操作方法(這個
策略顯然小於等於 k 步)操作這些開關。B 君想知道按照這個策略(也就是先隨機操作,最後小於等於 k 步,使
用操作次數最小的操作方法)的操作次數的期望。這個期望可能很大,但是 B 君發現這個期望乘以 n 的階乘一定
是整數,所以他只需要知道這個整數對 100003 取模之後的結果。
Input
第一行兩個整數 n, k。
接下來一行 n 個整數,每個整數是 0 或者 1,其中第 i 個整數表示第 i 個燈的初始情況。
1 ≤ n ≤ 100000, 0 ≤ k ≤ n;
Output
輸出一行,爲操作次數的期望乘以 n 的階乘對 100003 取模之後的結果。
Sample Input
4 0
0 0 1 1
Sample Output
512
Solution
看完題面就覺得這題非常的喪。
先考慮不隨機按按鈕的情況。
我們發現在最優情況下,我們按編號從大到小的順序關燈,這樣的步數是最小的,因爲編號小的燈的按鈕開關不會影響編號大的燈的開關,這樣最壞情況下我們只要按 次就可以關閉所有燈。
然後我們發現, 的數據 ,這不是送分嗎,先打了再說。
就按編號從大到小 一遍, 如果這盞燈是開着的把所有編號爲它的因數的燈都按一遍,最後統計就可以了。
如果我們求出的最優解 大於 該怎麼辦呢。
我們設 爲我們需要按 次按鈕時能結束的期望步數。
易得我們有 的概率按到我們需要的按鈕 的概率按到我們不需要的按鈕。
於是 .
然而我們發現,我們最多有 個方程而要求解 個變量,這顯然是不可行的。
所以我們把 數組差分一下, 設 。
整理得
最後答案爲
Code
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iostream>
#include <queue>
#include <set>
#include <stack>
#define R register
#define ll long long
#define db double
#define sqr(_x) (_x) * (_x)
#define Cmax(_a, _b) ((_a) < (_b) ? (_a) = (_b), 1 : 0)
#define Cmin(_a, _b) ((_a) > (_b) ? (_a) = (_b), 1 : 0)
#define Max(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#define Min(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define Abs(_x) (_x < 0 ? (-(_x)) : (_x))
using namespace std;
namespace Dntcry
{
inline int read()
{
R int a = 0, b = 1; R char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) (c == '-') ? b = -1 : 0;
for(; c >= '0' && c <= '9'; c = getchar()) a = (a << 1) + (a << 3) + c - '0';
return a * b;
}
inline ll lread()
{
R ll a = 0, b = 1; R char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) (c == '-') ? b = -1 : 0;
for(; c >= '0' && c <= '9'; c = getchar()) a = (a << 1) + (a << 3) + c - '0';
return a * b;
}
const int Maxn = 100010, Mod = 100003;
int n, k;
int v[Maxn];
ll f[Maxn], test, Ans, fac, inv[Maxn];
int Main()
{
n = read(), k = read();
fac = inv[0] = inv[1] = 1;
for(R int i = 1; i <= n; i++) v[i] = read(), fac = 1ll * fac * i % Mod;
for(R int i = n; i > 0; i--) if(v[i])
{
R int lim = (int)sqrt(i);
++test;
for(R int j = 1; j <= lim; j++)
if(i % j == 0)
{
v[j] ^= 1;
if(j * j != i) v[i / j] ^= 1;
}
}
if(test <= k) return !printf("%lld\n", test * fac % Mod);
for(R int i = 2; i <= n; i++)
inv[i] = (Mod - Mod / i) * inv[Mod % i] % Mod;
f[n] = 1;
for(R int i = n - 1; i >= k; i--)
f[i] = 1ll * (n + 1ll * (n - i) * f[i + 1] % Mod) * inv[i] % Mod;
for(R int i = test; i > k; i--) Ans = (Ans + f[i]) % Mod;
Ans += k;
printf("%lld\n", Ans * fac % Mod);
return 0;
}
}
int main()
{
return Dntcry :: Main();
}