Rating
题解
可怜的我考场上拿了0分
首先看到这道题了,我们容易定义出一个比较简单的
d
p
dp
dp,用
d
p
i
,
j
dp_{i,j}
dpi,j表示较大数为
i
i
i,较小的数为
j
j
j的概率。
本来定义到这里就可以了,我们将所有状态的概率直接加起来就可以得到答案了,这里为了方便我们再多定义一个
g
p
i
,
j
gp_{i,j}
gpi,j表示到达该状态的期望步数。
然后,我们可以简单地写出它的转移方程式:
p
k
d
p
i
,
j
→
d
p
i
,
j
+
k
/
d
p
i
+
k
,
j
p
k
(
g
p
i
,
j
+
d
p
i
,
j
)
→
g
p
i
,
j
+
k
/
g
p
i
+
k
,
j
p_kdp_{i,j}\rightarrow dp_{i,j+k}/dp_{i+k,j}\\ p_k(gp_{i,j}+dp_{i,j})\rightarrow gp_{i,j+k}/gp_{i+k,j}
pkdpi,j→dpi,j+k/dpi+k,jpk(gpi,j+dpi,j)→gpi,j+k/gpi+k,j注意,第二个方程的位置必须是加上
d
p
i
,
j
dp_{i,j}
dpi,j,因为前面的
g
p
i
,
j
gp_{i,j}
gpi,j表示的是每种路径被使用的概率乘上每种路径的长度,扩展一步就是每种情况。
所以这里加上的应该是到达该点的概率,而不是
1
1
1。
由于下一层的值是不会影响上一层的,我们可以先将每一层的
d
p
dp
dp值消元解出后,再去解下一层的方程。
接着方程我们事实上最多也只能优化到
O
(
m
n
3
)
O\left(mn^3\right)
O(mn3),看起来不太像能过的样子,我们考虑优化。
如果真要优化的,显然也就不能用列方程组的方法了。
我们可以考虑一些顺推的
d
p
dp
dp,我们不妨再多定义一个
f
i
,
j
,
g
i
,
j
f_{i,j},g_{i,j}
fi,j,gi,j表示从
i
i
i出发走到第一个大于
i
i
i的点为
i
+
j
i+j
i+j的概率与期望花费。
考虑怎么将这东西快速地预处理出来,定义
h
i
,
j
,
h
p
i
,
j
h_{i,j},hp_{i,j}
hi,j,hpi,j表示从
i
i
i出发后不再走大于
j
j
j的点第一次走到
j
j
j概率与期望距离。
我们先枚举从
i
i
i出发走的第一步
k
k
k,将它贡献到
h
i
,
i
+
k
h_{i,i+k}
hi,i+k上,显然这个
i
+
k
i+k
i+k可能比
i
i
i小,也可能比
i
i
i大。
大丈夫です,对于比
i
i
i小的部分,它的
d
p
dp
dp值不是已经预处理出来了吗,它就可以从比较小的
h
j
h_j
hj贡献到较大的
h
k
(
k
>
j
)
h_k(k>j)
hk(k>j)。
这样,我们就能将
<
i
<i
<i出的
h
h
h值转移到
⩾
i
\geqslant i
⩾i处。
那么我们考虑,如何将这个
h
h
h算到我们的
f
f
f值上呢?显然,
h
i
,
i
h_{i,i}
hi,i相当于走了一个环,又走回到了
i
i
i上的概率与期望,而大于
i
i
i的部分会直接贡献到其它
f
f
f值的贡献。
可以计算出
f
i
,
j
f_{i,j}
fi,j对
f
i
,
k
/
f
k
,
i
(
k
>
j
)
f_{i,k}/f_{k,i}(k>j)
fi,k/fk,i(k>j)的贡献为
h
k
1
−
h
i
\frac{h_k}{1-h_i}
1−hihk,对
g
i
,
k
/
g
k
,
i
g_{i,k}/g_{k,i}
gi,k/gk,i的贡献为
h
p
k
(
1
−
h
i
)
+
h
p
i
h
k
(
1
−
h
i
)
2
\frac{hp_k(1-h_i)+hp_ih_{k}}{(1-h_i)^2}
(1−hi)2hpk(1−hi)+hpihk。
这样我们就可以在
O
(
n
m
2
)
O\left(nm^2\right)
O(nm2)的时间内完成我们的预处理。
有了上面的
f
f
f与
g
g
g,我们自然而然就很容易得到
d
p
dp
dp的转移方法。
显然,我们只需要枚举较小的数下一个变到的比他大的数是什么就行了。
这部分的转移就可以做到
O
(
n
m
2
)
O\left(nm^2\right)
O(nm2)。
总时间复杂度 O ( n m 2 ) O\left(nm^2\right) O(nm2)。
源码
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define MAXN 1055
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
typedef long double Ld;
typedef pair<int,int> pii;
const LL INF=0x3f3f3f3f3f3f3f3f;
const int mo=998244353;
const int mod=1e6+7;
const int inv2=499122177;
const int jzm=2333;
const int zero=100;
const int orG=3,ivG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-9;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0)putchar('-'),print(-x);if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;}return t;}
int n,m,val[105],g[MAXN][55],f[MAXN][55],ans;
int dp[MAXN][MAXN],gp[MAXN][MAXN],h[MAXN],hp[MAXN];
int main(){
read(n);read(m);int summ=0,iv8=qkpow(100000000,mo-2,mo);
for(int i=0;i<=m+m;i++)read(val[i]),val[i]=1ll*iv8*val[i]%mo;
for(int i=0;i<=m;i++)Add(summ,val[i],mo);
dp[0][0]=1;gp[0][0]=0;
for(int i=0;i<=n;i++){
for(int j=0;j<=m+m;j++)
Add(h[max(i+j-m,0)],val[j],mo),
Add(hp[max(i+j-m,0)],val[j],mo);
for(int j=max(0,i-m);j<i;j++)
for(int k=1;k<=m;k++)
Add(h[j+k],1ll*h[j]*f[j][k]%mo,mo),
Add(hp[j+k],1ll*hp[j]*f[j][k]%mo,mo),
Add(hp[j+k],1ll*h[j]*g[j][k]%mo,mo);
const int tp=qkpow(add(1,mo-h[i],mo),mo-2,mo);
for(int j=1;j<=m;j++)
f[i][j]=1ll*h[i+j]*tp%mo,
g[i][j]=1ll*add(hp[i+j],1ll*hp[i]*f[i][j]%mo,mo)*tp%mo;
for(int j=max(0,i-m);j<=i+m;j++)h[j]=hp[j]=0;
}
for(int i=0;i<n;i++)
for(int j=max(i-m,0);j<=i;j++){
for(int k=1;k<=m;k++)
if(j+k<=i)
Add(dp[i][j+k],1ll*dp[i][j]*f[j][k]%mo,mo),
Add(gp[i][j+k],1ll*dp[i][j]*g[j][k]%mo,mo),
Add(gp[i][j+k],1ll*gp[i][j]*f[j][k]%mo,mo);
else if(j+k<n)
Add(dp[j+k][i],1ll*dp[i][j]*f[j][k]%mo,mo),
Add(gp[j+k][i],1ll*dp[i][j]*g[j][k]%mo,mo),
Add(gp[j+k][i],1ll*gp[i][j]*f[j][k]%mo,mo);
else if(j+k>=n)
Add(ans,1ll*dp[i][j]*g[j][k]%mo,mo),
Add(ans,1ll*gp[i][j]*f[j][k]%mo,mo);
}
printf("%d\n",ans);
return 0;
}