你现在有m+1个数:第一个为p,最小值为0,最大值为n;剩下m个都是无穷,没有最小值或最大值。
你可以进行任意多轮操作,每轮操作如下:
在不为最大值的数中等概率随机选择一个(如果没有则不操作),把它加一;
进行k次这个步骤:在不为最小值的数中等概率随机选择一个(如果没有则不操作),把它减一。
现在问期望进行多少轮操作以后第一个数会变为最小值0。
输入包含多组数据。
输入第一行包含一个正整数T,表示数据组数。
接下来T行,每行4个非负整数n、p、m、k(含义见题目描述),表示一次询问。
1≤T≤100
1≤p≤n≤1500
0≤m,k≤1000000000 。
保证不存在n=p=k=1 ,m=0 的情况(因为出题人判错了)
保证不存在答案的分母是1000000007 的倍数的情况(因为出题人没想到)
输出T行,每行一个整数,表示一次询问的答案。
如果无论进行多少轮操作,第一个数都不会变为最小值0,那么输出-1;
否则,可以证明答案一定为有理数,那么请输出答案模1000000007的余数,
即设答案为b/a(a、b为互质的正整数),你输出的整数为x,
那么你需要保证0≤x<1000000007且a≡bx mod 1000000007
2
2 1 1 1
2 2 1 1
6
8
首先设 f[i] f [ i ] 为 k k 次攻击击中英雄 i i 次的概率,即 f[i]=(ki)(1m+1)i(mm+1)k−i f [ i ] = ( k i ) ( 1 m + 1 ) i ( m m + 1 ) k − i
设 dp[i] d p [ i ] 为还剩 i i 滴血时期望多少轮挂掉,则 dp[0]=0 d p [ 0 ] = 0 。
当 1<i<n 1 < i < n ,
注意 m=0 m = 0 要特判。
时间复杂度 O(Tn2) O ( T n 2 )
#include
#define ll long long
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
if(c=='-')c=getchar(),f=-1;
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=1505,mod=1e9+7;
ll n,p,m,k,f[N];
inline ll add(ll x,ll y){return x+y>mod?x+y-mod:x+y;}
struct data
{
ll x,y;
data(ll _x=0,ll _y=0):x(_x),y(_y){}
inline data operator + (const data &b){return data(add(x,b.x),add(y,b.y));}
inline data operator - (const data &b){return data(add(x,-b.x+mod),add(y,-b.y+mod));}
inline data operator * (const ll &b){return data(x*b%mod,y*b%mod);}
}dp[N];
ll Pow(ll x,ll y)
{
ll res=1;
for(;y;y>>=1,x=x*x%mod)
if(y&1)res=res*x%mod;
return res;
}
ll solve1()
{
if(k==1&&n!=1)return -1;
f[0]=0;
for(int i=1;i1-k,0ll)]+1;
f[n]=f[max(n-k,0ll)]+1;
return f[p];
}
ll solve()
{
n=getint(),p=getint(),m=getint(),k=getint();
if(k==0)return -1;
if(!m)return solve1();
ll invm=Pow(m,mod-2),x=min(k,n);
f[0]=Pow(m*Pow(m+1,mod-2)%mod,k);if(f[0]==0||f[0]==1)return -1;
for(int i=1;i<=x;i++)f[i]=f[i-1]*(k-i+1)%mod*Pow(i,mod-2)%mod*invm%mod;
ll finv=Pow(f[0],mod-2);
dp[0]=data(0,0),dp[1]=data(1,0);
for(int i=1;i1]=data(dp[i].x,dp[i].y-1)*(m+1);
x=min((ll)i,k);
for(int j=0;j<=x;j++)dp[i+1]=dp[i+1]-(dp[i-j]*f[j])*m;
x=min((ll)i+1,k);
for(int j=1;j<=x;j++)dp[i+1]=dp[i+1]-dp[i+1-j]*f[j];
dp[i+1]=dp[i+1]*finv;
}
data t=data(0,1);x=min(n,k);
for(int j=1;j<=x;j++)t=t+dp[n-j]*f[j];
t=t*Pow(1-f[0]+mod,mod-2),t=t-dp[n];
if(t.x==0&&dp[p].x)return -1;
ll X=0;if(t.x)X=(mod-t.y)*Pow(t.x,mod-2)%mod;
return (dp[p].x*X%mod+dp[p].y)%mod;
}
int main()
{
//freopen("heal.in","r",stdin);
//freopen("heal.out","w",stdout);
for(int T=getint();T;T--)cout<'\n';
}