题解
好题,但是这个解法适用范围比较窄,也没有多大的用处 ____by Freopen
我们先把p数组写成概率生成函数的形式,设
我们发现x^i的系数表示我们走一步到位置 i 的概率是多少
那么P^2(x)中x^i的系数就表示我们走2步到位置 i 的概率是多少
我们发现答案的概率生成函数(设为Q(x))就是P^n(x),设
最后我们只需要保留一下前面的0~t项(这里我们替换一下变量,原题用的x与生成函数用的x重复了)
答案就是
所以我们有了一个暴力的做法——多项式快速幂O(n*t)
可以用NTT优化一下做到O(t*logn)
然而只有40分(话说这部分分也太少了吧)
接下来我们就进入开挂模式(也许这是一个数学中的常用套路吧。。)
(求导的链式法则)
(乘法的求导)
于是我们就有了
然后把它们展开
由待定系数法可知,左右同次的x的系数是相等的
设s=i+j,则x^s的系数可以表示为
我们把右边j=0的那一项单独提出来
移一下项
换一下求和的范围
最终得到:
所以
令s=s+1
则
这样就可以O(k*t)计算q数组了
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 100000005
const int mod=998244353;
int inv[N],f[N],p[105];
int ksm(int x,int y)
{
int ret=1;
while(y){
if(y&1)ret=1ll*ret*x%mod;
y>>=1;x=1ll*x*x%mod;
}
return ret;
}
int main()
{
int n,k,t,i,j,s=0,ans=0;
int ip0;
scanf("%d%d%d",&n,&k,&t);
for(i=0;i<=k;i++){scanf("%d",&p[i]);s+=p[i];}
s=ksm(s,mod-2);
for(i=0;i<=k;i++)p[i]=1ll*p[i]*s%mod;
ip0=ksm(p[0],mod-2);
f[0]=ksm(p[0],n);
ans=-1ll*t*f[0]%mod;
for(i=1;i<=t;i++){
if(i==1)inv[i]=1;
else inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
int sum=0;
for(j=1;j<=k&&j<=i;j++)
sum=(1ll*sum+1ll*(1ll*p[j]*j%mod*n%mod-1ll*p[j]*(i-j)%mod+1ll*mod)%mod*f[i-j])%mod;
f[i]=1ll*sum*ip0%mod*inv[i]%mod;
ans=(1ll*ans+1ll*f[i]*(i-t))%mod;
}
printf("%d\n",((1ll*ans+1ll*t)%mod+mod)%mod);
}