[BZOJ2019]光线 题解
老规矩,自己去看题面
状态设计
我当时看到这道题的时候,我的第一反应竟然是:袜!这道题长得好像DP啊! 于是我开始尝试设计状态:
我们令 \(f[i]\) 表示经过第 \(i\) 层玻璃向下走的光线量, \(g[i]\) 表示经过第 \(g[i]\) 表示经过第 \(i\) 层玻璃向上走的光线量。
初值
根据定义我们可以得到:
转移方程
于是我们得到转移方程 ( 为了方便表述,下列方程中 \(\%\) 均省略 ):
然后我们就可以开开心心的转移啦 (大雾
上述式子中我们观察到式子中包含了\(g[i + 1]\) 是当前未知量 ( 如果我们是正推的话 ),并不能直接递推转移,所以我们试图消去这一未知数。
我们注意到:g当 \(i == n\) 时有:
于是我们就得到了一个 \(f[n]\) 和 \(g[n]\) 关于 \(f[n - 1]\) 的正比例函数表述形式。
我们考虑是否能将该形式推广到 \(i \in [1, \; n]\),于是我们根据原始方程写出关于 \(n - 1\) 的方程:
我们将 \(g[n]\) 代入得:
我们将 \((1)\) 式移项后合并同类项得:
再把因数除过去得:
将上式代入 \((2)\) 式可得:
合并同类相得:
将 \((3)(4)\) 式换元后可得:
此时我们注意到我们已经将 \(\forall i \in[1, \; n]\) 我们都可以表示为等比例函数形式了,于是我们想到记 \(F[i] = \frac{f[i]}{f[i - 1]}, \; G[i] = \frac{g[i]}{f[i - 1]}\) ( 千万注意,这里的 \(G\) 中分母处是\(f\),看上面的方程你就知道为啥了 ) ,也就是说我们可以得到方程:
注意:上面的 \(g\) 函数不是笔误,右边就是 \(f\)。
我们回到原方程中去看:
先代入计算 \(f\) 方程可得:
同样的我们移项合并再除回来可得:
于是我们得到 ( 把 \(f[i - 1]\) 除过去 ):
然后我们再看 \(g\) 方程:
于是我们得到:
显然 \(F[i]\) 我们上面已经求出了可以直接用了 ( 所以我们代码里计算顺序很重要)。
最后我们得出:
这道题就到此结束了。
代码
注:以下代码中的小写 \(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;
}

浙公网安备 33010602011771号