[BZOJ2019]光线 题解

老规矩,自己去看题面

状态设计

我当时看到这道题的时候,我的第一反应竟然是:袜!这道题长得好像DP啊! 于是我开始尝试设计状态:

我们令 \(f[i]\) 表示经过第 \(i\) 层玻璃向下走的光线量, \(g[i]\) 表示经过第 \(g[i]\) 表示经过第 \(i\) 层玻璃向上走的光线量。

初值

根据定义我们可以得到:

\[f[0] = 1, \; g[n + 1] = 0 \]

转移方程

于是我们得到转移方程 ( 为了方便表述,下列方程中 \(\%\) 均省略 ):

\[f[i] = f[i - 1] * a[i] + g[i + 1] * b[i] \\ g[i] = f[i - 1] * b[i] + g[i + 1] * a[i] \]

然后我们就可以开开心心的转移啦 (大雾
上述式子中我们观察到式子中包含了\(g[i + 1]\) 是当前未知量 ( 如果我们是正推的话 ),并不能直接递推转移,所以我们试图消去这一未知数。

我们注意到:g当 \(i == n\) 时有:

\[f[n] = f[n - 1] * a[n] \\ g[n] = f[n - 1] * b[n] \]

于是我们就得到了一个 \(f[n]\) 和 \(g[n]\) 关于 \(f[n - 1]\) 的正比例函数表述形式。

我们考虑是否能将该形式推广到 \(i \in [1, \; n]\),于是我们根据原始方程写出关于 \(n - 1\) 的方程:

\[f[n - 1] = f[n - 2] * a[n - 1] + g[n] * b[n - 1] \\ g[n - 1] = f[n - 2] * b[n - 1] + g[n] * a[n - 1] \]

我们将 \(g[n]\) 代入得:

\[f[n - 1] = f[n - 2] * a[n - 1] + f[n - 1] * b[n] * b[n - 1] \;\;\;\;\; (1) \\ g[n - 1] = f[n - 2] * b[n - 1] + f[n - 1] * b[n] * a[n - 1] \;\;\;\;\; (2) \]

我们将 \((1)\) 式移项后合并同类项得:

\[f[n - 1] * (1 - b[n] * b[n - 1]) = f[n - 2] * a[n - 1] \]

再把因数除过去得:

\[f[n - 1] = f[n - 2] * \frac{a[n - 1]}{1 - b[n] * b[n - 1]} \;\;\;\;\;(3) \]

将上式代入 \((2)\) 式可得:

\[g[n - 1] = f[n - 2] * b[n - 1] + f[n - 2] * \frac{a[n - 1]}{1 - b[n] * b[n - 1]} * b[n] * a[n - 1] \]

合并同类相得:

\[g[n - 1] = f[n - 2] * (b[n - 1] + \frac{a[n - 1]}{1 - b[n] * b[n - 1]} * b[n] * a[n - 1] ) \;\;\;\;\;(4) \]

将 \((3)(4)\) 式换元后可得:

\[f[i] = f[i - 1] * \frac{a[i]}{1 - b[i + 1] * b[i]} \\ g[i] = f[i - 1] * (b[n - 1] + \frac{a[i]}{1 - b[i + 1] * b[i]} * b[i + 1] * a[i] ) \]

此时我们注意到我们已经将 \(\forall i \in[1, \; n]\) 我们都可以表示为等比例函数形式了,于是我们想到记 \(F[i] = \frac{f[i]}{f[i - 1]}, \; G[i] = \frac{g[i]}{f[i - 1]}\) ( 千万注意,这里的 \(G\) 中分母处是\(f\),看上面的方程你就知道为啥了 ) ,也就是说我们可以得到方程:

\[f[i] = f[i - 1] * F[i] \\ g[i] = f[i - 1] * G[i] \]

注意:上面的 \(g\) 函数不是笔误,右边就是 \(f\)。

我们回到原方程中去看:

\[f[i] = f[i - 1] * a[i] + g[i + 1] * b[i] \\ g[i] = f[i - 1] * b[i] + g[i + 1] * a[i] \]

先代入计算 \(f\) 方程可得:

\[f[i] = f[i - 1] * a[i] + f[i] * G[i + 1] * b[i] \]

同样的我们移项合并再除回来可得:

\[f[i] = f[i - 1] * \frac{a[i]}{1 - G[i + 1] * b[i]} \]

于是我们得到 ( 把 \(f[i - 1]\) 除过去 ):

\[F[i] = \frac{a[i]}{1 - G[i + 1] * b[i]} \]

然后我们再看 \(g\) 方程:

\[g[i] = f[i - 1] * b[i] + f[i] * G[i + 1] * a[i] \\ \implies g[i] = f[i - 1] * b[i] + f[i - 1] * F[i] * G[i + 1] * a[i] \\ \implies g[i] = f[i - 1] * (b[i] + F[i] * G[i + 1] * a[i]) \]

于是我们得到:

\[G[i] = b[i] + F[i] * G[i + 1] * a[i] \]

显然 \(F[i]\) 我们上面已经求出了可以直接用了 ( 所以我们代码里计算顺序很重要)。

最后我们得出:

\[f[n] = f[0] * F[1] * F[2] * ... * F[n] \]

这道题就到此结束了。

代码

注:以下代码中的小写 \(f, \; g\) 均为上述方程中的大写 \(F, \; G\)。

//省略快读和头文件

int pls(int x, int y)
{
	if(x + y >= MOD)
		return x + y - MOD;
	else
		return x + y;
}
int mul(int x, int y)
{
	if(1ll * x * y >= MOD)
		return 1ll * x * y % MOD;
	else
		return x * y;
}
int dec(int x, int y)
{
	if(x - y < 0)
		return x - y + MOD;
	else
		return x - y;
}

int qpow(int x, int y)
{
	int val = 1;
	while(y) {
		if(y & 1)
			val = mul(val, x);
		
		x = mul(x, x);
		y >>= 1;
	}
	return val;
}

int inv100;
int n;
int a[MAXN], b[MAXN];

int f[MAXN], g[MAXN]; 

int main()
{
	inv100 = qpow(100, MOD - 2);
	n = inpt();
	for(int i = 1; i <= n; i++) {
		a[i] = inpt(), b[i] = inpt();
		a[i] = mul(a[i], inv100), b[i] = mul(b[i], inv100);
	}
	
	for(int i = n; i >= 1; i--) {
		f[i] = mul(a[i], qpow(dec(1, mul(g[i + 1], b[i])), MOD - 2));
		g[i] = pls(b[i], mul(f[i], mul(g[i + 1], a[i])));
	}
	int ans = 1;
	for(int i = 1; i <= n; i++) {
		ans = mul(ans, f[i]);
	}
	
	printf("%d", ans);
	return 0;
}

posted @ 2022-07-30 22:39  YunYuanWang  阅读(52)  评论(0)    收藏  举报