題意:
B 君在玩一個遊戲,這個遊戲由 n 個燈和 n 個開關組成,給定這 n 個燈的初始狀態,下標爲從 1 到 n 的正整數。
每個燈有兩個狀態亮和滅,我們用 1 來表示這個燈是亮的,用 0 表示這個燈是滅的,遊戲的目標是使所有燈都滅掉。
但是當操作第 i 個開關時,所有編號爲 i 的約數(包括 1 和 i)的燈的狀態都會被改變,即從亮變成滅,或者是從滅變成亮。
B 君發現這個遊戲很難,於是想到了這樣的一個策略,每次等概率隨機操作一個開關,直到所有燈都滅掉。
這個策略需要的操作次數很多, B 君想到這樣的一個優化。如果當前局面,可以通過操作小於等於 k 個開關使所有燈都滅掉,那麼他將不再隨機,直接選擇操作次數最小的操作方法(這個策略顯然小於等於 k 步)操作這些開關。
B 君想知道按照這個策略(也就是先隨機操作,最後小於等於 k 步,使用操作次數最小的操作方法)的操作次數的期望。
這個期望可能很大,但是 B 君發現這個期望乘以 n 的階乘一定是整數,所以他只需要知道這個整數對 100003 取模之後的結果。
1 ≤ n ≤ 100000; 0 ≤ k ≤ n
Solution:
日常被期望題艹爆…
首先考慮當前狀態達到遊戲目標的最小步數:對於一個數i,小於他的位置開關一定不會對它產生影響,所以可能影響到它的只有它前面和它本身,那麼我們可以知道從後往前關燈一定是最優的,暴力搞就行
需要篩出每個數的因數,複雜度
下面我們再來看期望:f[i]表示從達到遊戲目標的最小步數爲i變爲達到遊戲目標的最小步數爲i-1的期望操作次數
因爲對於每個不同狀態到達遊戲目標所需操作的開關都是唯一的,那麼就有轉移:
(n個開關中有i個是可以減少步數的開關,剩餘的n-i個會增加一步)
移項得:
再考慮我們的初始狀態:當所有位置都爲正確選擇時,選任何一個位置都不會增加錯誤選擇,所以f[n]=1
最後把f[k+1]~f[到達遊戲目標的最小步數]累加起來即可
代碼:
#include<cstdio>
#include<vector>
#include<iostream>
using namespace std;
const int mod=100003;
vector<int>d[100010];
int n,m,stp;
int a[100010];
int f[100010];
int fast_pow(int x,int a)
{
int ans=1;
for (;a;a>>=1,x=1ll*x*x%mod)
if (a&1) ans=1ll*ans*x%mod;
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
for (int i=1;i<=n;i++)
for (int j=i;j<=n;j+=i) d[j].push_back(i);
for (int i=n;i>=1;i--)
if (a[i])
{
stp++;
for (int j=0;j<d[i].size();j++)
a[d[i][j]]^=1;
}
int ans=0;
if (stp<=m) ans=stp;
else
{
f[n]=1;
for (int i=n-1;i>m;i--) f[i]=(1ll*n+1ll*(n-i)*f[i+1])%mod*fast_pow(i,mod-2)%mod;//,cout<<f[i]<<" ";
ans=m;
for (int i=m+1;i<=stp;i++) {ans+=f[i];if (ans>=mod) ans-=mod;}
}
for (int i=1;i<=n;i++) ans=1ll*ans*i%mod;
printf("%d",ans);
}