抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

题解 : Two Frogs

1. 题意

地址:https://ac.nowcoder.com/acm/contest/33194/B

1.1 题目描述

In the Lonely Mountain, there are a lot of treasure well protected by dwarfs. Later, one day, the last dragon Smaug came and sensed the treasure being. As known to all, dragons are always much too greedy for treasure. So definitely, the war between dwarfs and Smaug begins.

During the war, two goblins Alice and Bob are turned into frogs by Gandalf, The Grey. In front of them, there are nnn lotus leaves in a line. In order to break the spell, they must jump from the 1-st lotus leaf to the nnn-th lotus leaf. If the frog is now on the i-th lotus leaf instead of the n-th lotus leaf, it can jump to a lotus leaf in range $(i,i+a_i]$.

Goblins are lack of intelligence and it’s also true even after turned into frogs. So Alice and Bob will jump randomly, which means, they will separately pick an available lotus leaf in every jump uniformly at random.

Since Alice and Bob have already being playing games for decades, so they want to know the probability that they jump to the nnn-th lotus leaf with the same count of jumps.

1.2 输入描述:

The first line contains an integer n (2≤n≤8 000), denoting the number of lotus leaf.

The second line contains n−1 integers $a_1,a_2$,…,$a_{n−1}$, where the i-th integer (1≤$a_i$≤n−i) indicates the range of lotus leaves that can be reached from the i-th lotus leaf.

1.3输出描述:

Output a line containing a single integer, indicating the probability that Alive and Bob jump to nnn-th lotus leaf with the same count of jumps, taken modulo 998,244,353.

Formally speaking, let the result, which is a rational number, be $\frac{x}{y}$ as an irreducible fraction, you need to output x⋅y−1 mod 998 244 353, where y−1 is a number such that $y \cdot y^{-1} \equiv 1 \pmod{998,244,353}$. You may safely assume that such $y^{-1}$ always exists.

2.思路

2.1 状态设计与转移方程

显而易见的我们可以得到一个 o($n^3$) 的状态设计和转移方程。令$f[i][j]$表示跳了i次恰好跳到j这个位置的概率。所求答案是
$$
\sum_{i=1}^{n}f[i][n]^2
$$
显而易见的转移方程是:
$$
f[i+1][j+k]=f[i][j]\times\frac{1}{a[j]},k\in [1,a[j]]
$$
在这个过程中注意取模,$\frac{1}{a[j]}$ 要变成 inv(a[j])。这一部分可以线性的预处理出来

2.2 优化

我们不能接受o($n^3$) 的时间复杂度与o($n^2$)的空间复杂度。在方程中枚举k是为了给后面的区间全部加上一个值。我们可以容易的想到使用前缀和进行优化。

当然还可以更轻易地想到使用滚动数组优化以后再使用树状数组或线段树一类的数据结构维护区间信息,当然这样会t,别问怎么知道的

只需要给需要区间加的区间的左端点加上要加的值,在右端点减去这个值。求前缀和的时候就完成了区间加的操作。

另外需要使用滚动数组优化空间复杂度。

3.代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN=8e3+7,P=998244353;
long long f[MAXN],sum[MAXN],inv[MAXN],a[MAXN];
template <typename _TP>
inline _TP qread(_TP &X){
char ch=0;int w;X=0;
while(!isdigit(ch)){w=ch=='-';ch=getchar();}
while(isdigit(ch)){X=(X<<1)+(X<<3)+(ch^48);ch=getchar();}
X=w?-X:X;
return X;
}
int main(){
int n;
qread(n);
inv[1]=1;
for(int i=2;i<=n;i++){
inv[i]=((P-P/i)*inv[P%i])%P;
}
for(int i=1;i<n;i++){
qread(a[i]);
}
f[1]=1;
long long ans=0;
for(int i=0;i<=n;i++){
for(int j=1;j<=n;j++){
sum[j]+=sum[j-1];
sum[j]%=P;
}
f[n]=(f[n]+sum[n])%P;
ans=(ans+(f[n]*f[n])%P)%P;
f[n]=0;sum[n]=0;
for(int j=n-1;j>=1;j--){
f[j]=(f[j]+sum[j])%P;
sum[j+1]=(sum[j+1]+(f[j]*inv[a[j]])%P)%P;
sum[j+a[j]+1]=(sum[j+a[j]+1]-(f[j]*inv[a[j]])%P+P)%P;
f[j]=0;sum[j]=0;
}
}
cout<<ans;
return 0;
}

评论