[BJOI2019]光线 题解

21 篇文章 0 订阅

老规矩,自己去看题面

状态设计

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

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

初值

根据定义我们可以得到:
f [ 0 ] = 1 ,    g [ n + 1 ] = 0 f[0] = 1, \; g[n + 1] = 0 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 ] 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[i]=f[i1]a[i]+g[i+1]b[i]g[i]=f[i1]b[i]+g[i+1]a[i]
然后我们就可以开开心心的转移啦 (大雾
上述式子中我们观察到式子中包含了 g [ i + 1 ] g[i + 1] g[i+1] 是当前未知量 ( 如果我们是正推的话 ),并不能直接递推转移,所以我们试图消去这一未知数。

我们注意到:g当 i = = n i == n i==n 时有:
f [ n ] = f [ n − 1 ] ∗ a [ n ] g [ n ] = f [ n − 1 ] ∗ b [ n ] f[n] = f[n - 1] * a[n] \\ g[n] = f[n - 1] * b[n] f[n]=f[n1]a[n]g[n]=f[n1]b[n]
于是我们就得到了一个 f [ n ] f[n] f[n] g [ n ] g[n] g[n] 关于 f [ n − 1 ] f[n - 1] f[n1] 的正比例函数表述形式。

我们考虑是否能将该形式推广到 i ∈ [ 1 ,    n ] i \in [1, \; n] i[1,n],于是我们根据原始方程写出关于 n − 1 n - 1 n1 的方程:
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 ] 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] f[n1]=f[n2]a[n1]+g[n]b[n1]g[n1]=f[n2]b[n1]+g[n]a[n1]
我们将 g [ n ] g[n] 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 ) 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) f[n1]=f[n2]a[n1]+f[n1]b[n]b[n1](1)g[n1]=f[n2]b[n1]+f[n1]b[n]a[n1](2)
我们将 ( 1 ) (1) (1) 式移项后合并同类项得:
f [ n − 1 ] ∗ ( 1 − b [ n ] ∗ b [ n − 1 ] ) = f [ n − 2 ] ∗ a [ n − 1 ] f[n - 1] * (1 - b[n] * b[n - 1]) = f[n - 2] * a[n - 1] f[n1](1b[n]b[n1])=f[n2]a[n1]
再把因数除过去得:
f [ n − 1 ] = f [ n − 2 ] ∗ a [ n − 1 ] 1 − b [ n ] ∗ b [ n − 1 ]            ( 3 ) f[n - 1] = f[n - 2] * \frac{a[n - 1]}{1 - b[n] * b[n - 1]} \;\;\;\;\;(3) f[n1]=f[n2]1b[n]b[n1]a[n1](3)
将上式代入 ( 2 ) (2) (2) 式可得:
g [ n − 1 ] = f [ n − 2 ] ∗ b [ n − 1 ] + f [ n − 2 ] ∗ a [ n − 1 ] 1 − b [ n ] ∗ b [ n − 1 ] ∗ b [ n ] ∗ a [ n − 1 ] 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[n1]=f[n2]b[n1]+f[n2]1b[n]b[n1]a[n1]b[n]a[n1]
合并同类相得:
g [ n − 1 ] = f [ n − 2 ] ∗ ( b [ n − 1 ] + a [ n − 1 ] 1 − b [ n ] ∗ b [ n − 1 ] ∗ b [ n ] ∗ a [ n − 1 ] )            ( 4 ) 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) g[n1]=f[n2](b[n1]+1b[n]b[n1]a[n1]b[n]a[n1])(4)

( 3 ) ( 4 ) (3)(4) (3)(4) 式换元后可得:
f [ i ] = f [ i − 1 ] ∗ a [ i ] 1 − b [ i + 1 ] ∗ b [ i ] g [ i ] = f [ i − 1 ] ∗ ( b [ n − 1 ] + a [ i ] 1 − b [ i + 1 ] ∗ b [ i ] ∗ b [ i + 1 ] ∗ a [ i ] ) 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] ) f[i]=f[i1]1b[i+1]b[i]a[i]g[i]=f[i1](b[n1]+1b[i+1]b[i]a[i]b[i+1]a[i])

转移方程——递推方程

此时我们注意到我们已经将 ∀ i ∈ [ 1 ,    n ] \forall i \in[1, \; n] i[1,n] 我们都可以表示为等比例函数形式了,于是我们想到记 F [ i ] = f [ i ] f [ i − 1 ] ,    G [ i ] = g [ i ] f [ i − 1 ] F[i] = \frac{f[i]}{f[i - 1]}, \; G[i] = \frac{g[i]}{f[i - 1]} F[i]=f[i1]f[i],G[i]=f[i1]g[i] ( 千万注意,这里的 G G G 中分母处是 f f f,看上面的方程你就知道为啥了 ) ,也就是说我们可以得到方程:
f [ i ] = f [ i − 1 ] ∗ F [ i ] g [ i ] = f [ i − 1 ] ∗ G [ i ] f[i] = f[i - 1] * F[i] \\ g[i] = f[i - 1] * G[i] f[i]=f[i1]F[i]g[i]=f[i1]G[i]
注意:上面的 g g g 函数不是笔误,右边就是 f f 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[i] = f[i - 1] * a[i] + g[i + 1] * b[i] \\ g[i] = f[i - 1] * b[i] + g[i + 1] * a[i] f[i]=f[i1]a[i]+g[i+1]b[i]g[i]=f[i1]b[i]+g[i+1]a[i]
先代入计算 f f f 方程可得:
f [ i ] = f [ i − 1 ] ∗ a [ i ] + f [ i ] ∗ G [ i + 1 ] ∗ b [ i ] f[i] = f[i - 1] * a[i] + f[i] * G[i + 1] * b[i] f[i]=f[i1]a[i]+f[i]G[i+1]b[i]
同样的我们移项合并再除回来可得:
f [ i ] = f [ i − 1 ] ∗ a [ i ] 1 − G [ i + 1 ] ∗ b [ i ] f[i] = f[i - 1] * \frac{a[i]}{1 - G[i + 1] * b[i]} f[i]=f[i1]1G[i+1]b[i]a[i]
于是我们得到 ( 把 f [ i − 1 ] f[i - 1] f[i1] 除过去 ):
F [ i ] = a [ i ] 1 − G [ i + 1 ] ∗ b [ i ] F[i] = \frac{a[i]}{1 - G[i + 1] * b[i]} F[i]=1G[i+1]b[i]a[i]

然后我们再看 g g g 方程:
g [ i ] = f [ i − 1 ] ∗ b [ i ] + f [ i ] ∗ G [ i + 1 ] ∗ a [ i ]    ⟹    g [ i ] = f [ i − 1 ] ∗ b [ i ] + f [ i − 1 ] ∗ F [ i ] ∗ G [ i + 1 ] ∗ a [ i ]    ⟹    g [ i ] = f [ i − 1 ] ∗ ( b [ i ] + F [ i ] ∗ G [ i + 1 ] ∗ a [ i ] ) 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]=f[i1]b[i]+f[i]G[i+1]a[i]g[i]=f[i1]b[i]+f[i1]F[i]G[i+1]a[i]g[i]=f[i1](b[i]+F[i]G[i+1]a[i])
于是我们得到:
G [ i ] = b [ i ] + F [ i ] ∗ G [ i + 1 ] ∗ a [ i ] G[i] = b[i] + F[i] * G[i + 1] * a[i] G[i]=b[i]+F[i]G[i+1]a[i]
显然 F [ i ] F[i] F[i] 我们上面已经求出了可以直接用了 ( 所以我们代码里计算顺序很重要)。

最后我们得出:
f [ n ] = f [ 0 ] ∗ F [ 1 ] ∗ F [ 2 ] ∗ . . . ∗ F [ n ] f[n] = f[0] * F[1] * F[2] * ... * F[n] f[n]=f[0]F[1]F[2]...F[n]

这道题就到此结束了。

代码

注:以下代码中的小写 f ,    g f, \; g f,g 均为上述方程中的大写 F ,    G 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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值