传送门
解析:
还是一样的绕弯子,这道题求的是概率?不,是概率的期望。
首先所有人编号 − 1 -1 −1,这样好处理一些。
设 f [ i ] [ j ] f[i][j] f[i][j]表示上一个中弹的是第 j j j个人,当前还剩 i i i个人的时候 0 0 0号位置活到最后的概率。
边界状态 f [ 1 ] [ 0 ] = 1 f[1][0]=1 f[1][0]=1。
显然状态是分层+层内环状转移。
我们只考虑这一次中弹的人有没有活下来可以得到 f [ n ] [ j ] = 1 2 ( f [ n − 1 ] [ j + k − 1 ] + f [ n ] [ j + k ] ) f[n][j]=\frac{1}2(f[n-1][j+k-1]+f[n][j+k]) f[n][j]=21(f[n−1][j+k−1]+f[n][j+k])
直接暴力迭代可以发现环长为 l = n gcd ( n , k ) l=\frac{n}{\gcd(n,k)} l=gcd(n,k)n
可以发现暴力求解后有线性递推式:
f [ n ] [ j ] = 2 l 2 l − 1 ∑ i = 0 l − 1 f [ n − 1 ] [ ( j + i k − 1 ) % ( n − 1 ) ] 2 i + 1 f[n][j]=\frac{2^l}{2^l-1}\sum_{i=0}^{l-1}\frac{f[n-1][(j+ik-1)\%(n-1)]}{2^{i+1}} f[n][j]=2l−12li=0∑l−12i+1f[n−1][(j+ik−1)%(n−1)]
然后就可以 O ( n ) O(n) O(n)做了
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
using std::cout;
using std::cerr;
cs int mod=1e9+7,inv2=(mod+1)/2;
inline int add(int a,int b){return (a+b>=mod)?a+b-mod:a+b;}
inline int dec(int a,int b){return a<b?a-b+mod:a-b;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline int quickpow(int a,int b,int res=1){
while(b){
if(b&1)res=mul(res,a);
a=mul(a,a);
b>>=1;
}
return res;
}
cs int N=2e3+3;
int p2[N],ip2[N];
int a[N];
inline void solve(int *f,int n,int k){
int m=std::__gcd(n,k),l=n/m,coef=mul(p2[l],quickpow(p2[l]-1,mod-2));
for(int re i=0;i<m;++i){
int s=mul(a[i],inv2),t=1;
for(int re j=(i+k)%n;j!=i;j=(j+k)%n)
s=add(s,mul(a[j],ip2[++t]));
f[i]=mul(s,coef);
for(int re j=(i+n-k)%n;j!=i;j=(j+n-k)%n)
f[j]=mul(add(f[(j+k)%n],a[j]),inv2);
}
}
int n,k,f[N][N];
signed main(){
std::cin>>n>>k;
p2[0]=ip2[0]=1;
for(int re i=1;i<=n;++i)p2[i]=mul(p2[i-1],2),ip2[i]=mul(ip2[i-1],inv2);
f[1][0]=1;
for(int re t=2;t<=n;++t){
for(int re i=1;i<t;++i)a[i]=f[t-1][(i+k-1)%(t-1)];
solve(f[t],t,k%t);
}
cout<<f[n][(k-1)%n];
return 0;
}