题目链接
推下式子
假设就先不管加血
对
m
m
m个人随机搞
k
k
k次,掉
j
j
j第血的概率为
p
[
j
]
p[j]
p[j]
显然就是从
k
k
k次里选
j
j
j次刚他,得到公式
p
[
j
]
=
C
k
j
(
1
m
+
1
)
j
(
m
m
+
1
)
k
−
j
p[j]=C_k^j(\frac{1}{m+1})^j(\frac{m}{m+1})^{k-j}
p[j]=Ckj(m+11)j(m+1m)k−j
嘛,这个东西是可以递推出来的。
那么接着考虑奶的
显然把他从
i
i
i刚到
j
j
j要么掉了
i
−
j
+
1
i-j+1
i−j+1被奶了一口,要么掉了
i
−
j
i-j
i−j脸比较黑没有奶
p
p
[
i
]
[
j
]
=
1
m
+
1
p
[
i
−
j
+
1
]
+
m
m
+
1
p
[
i
−
j
]
pp[i][j]=\frac{1}{m+1}p[i-j+1]+\frac{m}{m+1}p[i-j]
pp[i][j]=m+11p[i−j+1]+m+1mp[i−j]
好的,然后开始考虑推期望,期望
E
[
i
]
E[i]
E[i]表示
i
i
i滴血被刚到0的期望步数
边界为
E
0
=
0
E_0=0
E0=0,因为已经凉了
E
i
=
(
∑
j
=
0
i
E
j
p
p
[
i
]
[
j
]
)
+
(
1
m
+
1
p
[
0
]
E
[
i
+
1
]
)
+
1
E_i=(\sum_{j=0}^iE_{j}pp[i][j])+(\frac{1}{m+1}p[0]E[i+1])+1
Ei=(∑j=0iEjpp[i][j])+(m+11p[0]E[i+1])+1
后面只有
1
m
+
1
\frac{1}{m+1}
m+11的原因是这个时候只能靠脸白被奶且无伤了
眉头一皱发现不大妙,他居然有i+1这个项
只好高斯消元了
消元的时候有点特殊技巧
可以发现这是一个梯形矩阵,一行比上一行多一个
那么消元可以行与行间消
复杂度O(n^2)
代码如下
#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
long long fac[2000],inv[2000];
long long f[1510],pp[1510][1510];
int n,p,m,k;
long long kasumi(long long a,long long b)
{
long long ans=1;
while(b)
{
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
void init()
{
fac[0]=1;
for(int i=1;i<=1700;i++)
{
fac[i]=fac[i-1]*i%mod;
}
inv[1700]=kasumi(fac[1700],mod-2);
for(int i=1699;i>=0;i--)
{
inv[i]=inv[i+1]*(i+1)%mod;
}
}
inline long long c(long long a,long long b)
{
return fac[a]*inv[b]%mod*inv[a-b]%mod;
}
int ttt;
int main()
{
// freopen("1.out","w",stdout);
init();
scanf("%d",&ttt);
while(ttt--)
{
memset(f,0,sizeof(f));
memset(pp,0,sizeof(pp));
scanf("%d%d%d%d",&n,&p,&m,&k);
if(k==0) {puts("-1");continue;}
if(m==0)
{
int ans=0;
if(k==1) {puts("-1");continue;}
if(p==n) {p-=k,ans++;}
for(;p>0;p-=k-1) ans++;
printf("%d\n",ans);
continue;
}
long long inv1=kasumi(m+1,mod-2);
long long tmp=1;
long long now=m*inv1%mod;
long long inv2=kasumi(m,mod-2);
now=kasumi(now,k);
f[0]=now;
for(int i=1;i<=n;i++)
{
f[i]=f[i-1]*inv2%mod*kasumi(i,mod-2)%mod*(k-i+1)%mod;
}
for(int i=1;i<n;i++)
{
for(int j=1;j<=i;j++)
{
pp[i][j]=(m*f[i-j]+f[i-j+1])%mod*inv1%mod;
}
}
for(int i=1;i<n;i++) pp[i][i+1]=f[0]*inv1%mod;
for(int i=1;i<n;i++) pp[i][i]=(pp[i][i]+mod-1)%mod;
for(int i=1;i<=n;i++) pp[i][n+1]=mod-1;
for(int i=1;i<=n;i++) pp[n][i]=f[n-i];
pp[n][n]=(pp[n][n]+mod-1)%mod;
for(int i=1;i<=n;i++)
{
inv1=kasumi(pp[i][i],mod-2);
pp[i][i]=1;
pp[i][n+1]=pp[i][n+1]*inv1%mod;
if(i!=n)
{
pp[i][i+1]=pp[i][i+1]*inv1%mod;
}
for(int j=i+1;j<=n;j++)
{
long long tmp=pp[j][i];
pp[j][i]=0;
pp[j][i+1]=(pp[j][i+1]-tmp*pp[i][i+1]%mod+mod)%mod;
pp[j][n+1]=(pp[j][n+1]-tmp*pp[i][n+1]%mod+mod)%mod;
}
}
for(int i=n;i>1;i--)
{
pp[i-1][n+1]=(pp[i-1][n+1]-pp[i-1][i]*pp[i][n+1]%mod+mod)%mod;
pp[i-1][i]=0;
}
printf("%lld\n",pp[p][n+1]);
}
}