罗曼诺夫统一了全世界,开创了人类的新纪元。
为了让子民们和罗曼诺夫一样卷,罗曼诺夫决定把一年设为 天,当中只有一天放假,也就是罗曼诺夫的生日。
然而,罗曼诺夫飞升之后,他的继承人却误解了罗曼诺夫的意思,没能继承罗曼诺夫的卷志。每一个继承人登基时都会把自己的生日设为假日,并且如果存在一天,它前后都是假日,那么这天也会被自动设为假日。 把 天看做一个环,也就是说第一天和第 天相邻。
我们假设每年会换一个继承人,所有人的生日都独立在 天中随机。
工作日逐渐减少,人民无所事事。当一年之中只剩下小于等于 天工作日的时候,国家终于崩溃了。
天上的罗曼诺夫预料到了这一切。请你帮他算一下,在亡国之前,每一年的权值之和的期望。
定义一年的权值为这一年中假期的总天数的 次方。
更加严谨的描述:从初始全都不是假日开始,令计数器 ,一直执行以下操作:
- 在 天中均匀随机一天,把它设为假日。
- 把两边都是假日的日期也变成假日。
- 设此时假日的个数为 s 。如果 那么退出循环,否则 并返回第一步。
求 的期望,对 取模。
。
注意到共有 天假日时有 段独立的连续假日段所有情况的概率都是一样的,所以可以设 表示共有 天假日时,有 段独立的连续假日段的所有情况的总概率,并且暂时先不考虑选择的假日之前被选过的情况。
设 表示有 天假日,分成 段独立的连续假日段的方案数,即 中共有多少种情况,显然可以用插板法快速求出,那么每种情况的概率即为 。
转移考虑下一次选择作为假日的是哪一天,首先所有转移的方案数和为 ,接下来分类讨论:
-
若下一次选择的日期把两个连续段连了起来:
-
消去长度为 的工作日段的方案数为 ,有转移
-
消去长度为 的工作日段的方案数为 ,有转移
-
-
若下一次选择的日期并入了某个连续段:
-
紧挨着之前的连续段的方案数为 ,有转移
-
和之前某个连续段之间只间隔一天的方案数为 ,有转移
-
-
下一次选择的日期单独开一个连续段的方案数即为 ,有转移
最后计算答案考虑期望在有 天假期时停留多少轮即可,利用等比数列求和公式推导,有:
代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
const int S=2005;
const int p=998244353;
int D,K,t;
int C[S][S],dp[S][S];
inline int qpow(int x,int y)
{
int res=1;
for(;y>0;y>>=1,x=1ll*x*x%p) res=y&1?1ll*res*x%p:res;
return res;
}
inline void add(int &x,int y)
{
x+=y;
if(x>=p) x-=p;
}
inline int inv(int x)
{
return qpow(x,p-2);
}
inline int calc(int n,int m)
{
int val=D-n;
if(val==0&&m==0) return 1;
if(val-m<=0||m<=0) return 0;
return C[val-m-1][m-1];
}
int main()
{
freopen("holiday.in","r",stdin);
freopen("holiday.out","w",stdout);
C[0][0]=1;
for(int i=1;i<=S-3;i++)
{
C[i][0]=1;
for(int j=1;j<=i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%p;
}
scanf("%d%d%d",&D,&K,&t);
dp[1][1]=1;
for(int i=1;i<=D-K-2;i++)
{
for(int j=1;j<=i;j++)
{
if(dp[i][j]==0) continue;
int all=1ll*(D-i)*calc(i,j)%p;
int ech=1ll*dp[i][j]*inv(calc(i,j))%p;
int de3=1ll*j*calc(i+3,j-1)%p;
int de2=1ll*2*j*calc(i+2,j-1)%p;
int wi1=1ll*2*j*calc(i+1,j)%p;
int wi2=1ll*2*j*calc(i+2,j)%p;
int lft=(((long long)all-de3-de2-wi1-wi2)%p+p)%p;
add(dp[i+3][j-1],1ll*ech*inv(D-i)%p*de3%p);
add(dp[i+2][j-1],1ll*ech*inv(D-i)%p*de2%p);
add(dp[i+1][j],1ll*ech*inv(D-i)%p*wi1%p);
add(dp[i+2][j],1ll*ech*inv(D-i)%p*wi2%p);
add(dp[i+1][j+1],1ll*ech*inv(D-i)%p*lft%p);
}
}
int ans=0;
for(int i=1;i<=D-K-1;i++)
{
int sum=0;
for(int j=1;j<=i;j++) add(sum,dp[i][j]);
add(ans,1ll*sum*qpow(i,t)%p*inv((1-1ll*i*inv(D)%p+p)%p)%p);
}
printf("%d\n",ans);
return 0;
}