[bzoj4872]分手是祝願
阿新 • • 發佈:2017-06-13
type 包括 ide lld 模擬 mod 接下來 ret bsp
第一行兩個整數 n, k。
接下來一行 n 個整數,每個整數是 0 或者 1,其中第 i 個整數表示第 i 個燈的初始情況。
1 ≤ n ≤ 100000, 0 ≤ k ≤ n;
0 0 1 1
的情況呢?
我們設f[i]為從"剩下i個位置亮按到到剩下i-1個位置亮"需要按的次數
那麽有2種情況
1°i/n的概率按到一個應該按的燈,直接成功
2°(n-i)/n的概率按到一個不應該按的燈,這時先要按回來到i,再按到i-1
所以f[i]=i/n+(n-i)/n*(b[i+1]+b[i]+1),再給它大力化簡一下,把f[i]放在一邊
得到:f[i]=(f[i+1]*(n-i)+n)/i
求出來之後,我們就要統計(k,num]間num的累加之和,再乘上階乘就完事了,ans=Σ{f[i],i∈(k,num]}*n!
如果n==k或者k>num,一上來就直接最優解,不用隨機,這時ans=num*n!
在計算的時候處理上取模(逆元之類的),就可以A掉這道題了
代碼見下:
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
Output
輸出一行,為操作次數的期望乘以 n 的階乘對 100003 取模之後的結果。Sample Input
4 00 0 1 1
Sample Output
512 題解: 熟悉的題目啊...(17年省選打醬油的回憶)這個題的靈魂就是期望式子的推導 我們先來考慮不隨機的情況: 我們應該從大編號往小編號(因為大編號只能按自己才能改變)一路按過去 這樣模擬一遍我們就可以算出來正常情況下要按多少次,設這個次數為num 那麽,如果考慮等概率瞎按#include<cstring> #include<cstdio> using namespace std; typedef long long LL; const int N=100010; const int mod=100003; int n,k,a[N]; LL f[N],num; LL quick_mod(LL di,int mi) { LL ret=1; while(mi) { if(mi&1)ret=ret*di%mod; di=di*di%mod; mi>>=1; } return ret; } int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=n;i>=1;i--) if(a[i]) { for(int j=1;j*j<=i;j++) if(!(i%j)) { a[j]^=1; if(j*j!=i)a[i/j]^=1; } num++; } for(LL i=n;i>=1;i--) f[i]=(f[i+1]*(n-i)%mod+n)%mod*quick_mod(i,mod-2)%mod; LL t=0; if(num<k||n==k)t=num; else { for(LL i=num;i>k;i--) t=(t+f[i])%mod; t=(t+k)%mod; } for(LL i=1;i<=n;i++) t=t*i%mod; printf("%lld",t); }bzoj4872
[bzoj4872]分手是祝願