【CF1523E】Crypto Lights
阿新 • • 發佈:2021-06-11
題目
題目連結:https://codeforces.com/contest/1523/problem/E
有 \(n\) 個檯燈初始時都是暗的,每次等概率隨機一個暗檯燈將其點亮,若點亮後存在一個長度為 \(k\) 的連續段有大於一個檯燈被點亮則立刻停止,求期望點亮多少檯燈。答案對 \(10^9+7\) 取模。
\(2\leq n,k\leq 10^5\)。
思路
記 \(f_i\) 表示選擇 \(i\) 次後結束的期望。那麼答案
\[=\sum^{n}_{i=1}f_i\times i=\sum^{n}_{i=1}\sum^{n}_{j=i}f_i \]考慮如何求出 \(g_i=\sum^{n}_{j=i+1}f_i\)
顯然 \(g_i\) 等價於選擇了 \(i\) 次依然沒有停止的期望。那麼問題轉化為有 \(n\) 個燈,選擇其中 \(i\) 個,兩兩之間距離大於等於 \(k-1\) 的期望。
我們可以把每一個燈看做一個長度為 \(k\) 的線段,那麼就是選擇 \(i\) 個長度為 \(k\) 的區間互相不交。注意最後一個區間的右端點是可以超過 \(n\) 的。
那麼我們直接把每一個區間的後 \(k-1\) 個元素刪掉,問題轉化為在 \(n-(i-1)(k-1)\) 個燈中選擇 \(i\) 個的方案數。這個東西和剛剛的模型是等價的。假設現在的模型中選擇了 \(i,j(i<j)\)
所以有 \[g_i=\frac{\binom{n-(i-1)(k-1)}{i}}{\binom{n}{i}} \]
答案就是 \(\sum^{n-1}_{i=0}g_i\)。
時間複雜度 \(O(Qn)\)。
程式碼
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=100010,MOD=1e9+7; int Q,n,k,ans,fac[N],inv[N]; ll fpow(ll x,ll k) { ll ans=1; for (;k;k>>=1,x=x*x%MOD) if (k&1) ans=ans*x%MOD; return ans; } ll C(ll n,int m) { if (n<m) return 0; return 1LL*fac[n]*inv[m]%MOD*inv[n-m]%MOD; } ll invC(int n,int m) { if (n<m) return 0; return 1LL*inv[n]*fac[m]%MOD*fac[n-m]%MOD; } int main() { fac[0]=inv[0]=1; for (int i=1;i<N;i++) fac[i]=1LL*fac[i-1]*i%MOD; inv[N-1]=fpow(fac[N-1],MOD-2); for (int i=N-2;i>=1;i--) inv[i]=1LL*inv[i+1]*(i+1)%MOD; scanf("%d",&Q); while (Q--) { scanf("%d%d",&n,&k); ans=1; for (int i=1;i<n;i++) ans=(ans+C(n-1LL*(i-1)*(k-1),i)*invC(n,i))%MOD; cout<<ans<<"\n"; } return 0; }