[dp优化][差分]Two Frogs 2022牛客多校第9场 B

125 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第14天,点击查看活动详情

题目描述

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 111-st lotus leaf to the nnn-th lotus leaf. If the frog is now on the iii-th lotus leaf instead of the nnn-th lotus leaf, it can jump to a lotus leaf in range (i,i+ai](i, i + a_i](i,i+ai​].

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.

输入描述:

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

The second line contains n−1n-1n−1 integers a1,a2,…,an−1a_1, a_2, \ldots, a_{n-1}a1​,a2​,…,an−1​, where the iii-th integer aia_iai​ (1≤ai≤n−i)(1 \leq a_i \leq n-i)(1≤ai​≤n−i) indicates the range of lotus leaves that can be reached from the iii-th lotus leaf.

输出描述:

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 353998,244,353998244353.

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

示例1

输入

5

1 1 1 1

输出

1

示例2

输入

5

4 3 2 1

输出

440198031

题意:

有n片荷叶依次排在水面上,第i片荷叶能够到达第[i+1, i+ai]片荷叶上,由于这两只青蛙比较笨,所以在某片荷叶上时它们会随机选择下一片可达范围内的荷叶,在从1号荷叶出发到达n号荷叶的过程中,求这两只青蛙有多大的概率以相同步数到达n号荷叶,两青蛙运动是相互独立的。

分析:

只需要求出一只青蛙到达n号荷叶的概率信息就可以了,设dp[i][j]表示从1号荷叶出发用i步走到j荷叶的概率,初始时显然dp[0][1] = 1,其余状态置0,之后可以比较容易地写出一个三重循环更新dp的代码,枚举下一次走到的位置计算贡献即可,但这样一定会TLE,所以还需要想办法优化,可以发现最内层循环其实就是一个区间加,不过是让dp[i+1][j+1]到dp[i+1][j+aj]都加上dp[i][j]/a[j]罢了,这种非动态的区间更新直接用差分处理就行,这样就优化掉了一重循环,不过要注意不能在那两层循环中求逆元,必须预处理出来,不然多个log也是会T的,最后就可以以O(n^2)的复杂度解决此题了。

具体代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
using namespace std;
 
int a[8005], dp[8005][8005];//从1用i步走到j的概率 
int c[8005], inv[8005];
const int mod = 998244353;
 
int ksm(int base, int power){
	int ans = 1;
	while(power){
		if(power&1) ans = 1ll*ans*base%mod;
		base = 1ll*base*base%mod;
		power >>= 1;
	}
	return ans;
}
 
signed main()
{
	int n;
	cin >> n;
	for(int i = 1; i <= n; i++)
		inv[i] = ksm(i, mod-2);
	for(int i = 1; i < n; i++)
		scanf("%d", &a[i]);
	dp[0][1] = 1;
	for(int i = 0; i <= n; i++){
		for(int j = 1; j <= n; j++)
			c[j] = ((dp[i+1][j]-dp[i+1][j-1])%mod+mod)%mod;
		for(int j = 1; j <= n; j++){
			c[j+1] = (c[j+1]+1ll*dp[i][j]*inv[a[j]]%mod)%mod;
			c[j+a[j]+1] = ((c[j+a[j]+1]-1ll*dp[i][j]*inv[a[j]]%mod)%mod+mod)%mod;
		}
		for(int j = 1; j <= n; j++)
			dp[i+1][j] = (dp[i+1][j-1]+c[j])%mod;
	}
	int ans = 0;
	for(int i = 1; i <= n; i++)
		ans = (ans+1ll*dp[i][n]*dp[i][n]%mod)%mod;
	cout << ans;
	
    return 0;	
}