THUPC 2023 B题拧螺丝 简要题解
-
本质构造
-
通过二分答案,我们知道,在已知用多少块板的情况下,我们肯定是尽可能让螺丝均分
-
这就告诉我们一个性质,木板上的螺丝只有两种可能, 要么是 \(Max\),要么是 \(Max - 1\)、、
-
考虑倒推答案
-
考虑维护一个三元组 \((x,y,z)\),表示当前最大值为 \(x\),最大值 \(x\) 个数为 \(y\), \((x - 1)\) 个数为 \(z\)
-
显然答案就是从 \((x-k,2,0) \to (0,0,0)\) 所需要的转移次数
-
考虑怎么转移(接下来就是平凡的讨论,自己画画图,就可以,难点在于要倒过来想):分两个情况, \(y \ge k\) 和 \(y < k\)
-
如果 \(y \ge k\),每次转移是
-
\(\begin{aligned} \\ \end{aligned}(x,y,z) \to (x - 1 - \frac{k-y}{y+z}, \\y + z + 1 - (k - y) \bmod (y + z),\\(k - y) \bmod (y + z))\)
-
(除法都是向下取整)
-
转移是很好理解的,首先我们消耗 \(k - y\) 次把最大值的螺丝拔掉,然后剩下的均匀拔掉 \((y + z)\) 个板中的螺丝,然后再增加一个最大值让老板拿掉
-
(要注意每次拔完 \(k\) 个螺丝后,都要留一个最大值让老板拿掉 (!!!注意,题目中是老板先拿走一个木板后,你再接着转螺丝,但是我们让时光倒流了,所以是先拔完螺丝,再增加一个 (拔完后的最大值,注意是拔完后的最大值,不是拔完前的) ))
-
然后 \(k < y\) 的情况就可以快速计算了,因为 \(k < y\) 的情况每个木板每次都只会拔一个钉子,(画个图模拟一下很容易看出转移方程)
代码如下:
import sys
sys.set_int_max_str_digits(100000)
n,k = map(int,input().split())
if k == 1:
if (n == 1):
print("1")
else:
print("Poor E.S.!")
elif k == 2:
print(2**(n-2))
else:
ans = 1
x = n - k
y = 2
z = 0
while (y <= k and x > 0):
tmp = (k - y) // (y + z)
mod = (k - y) - tmp * (y + z)
x = (x - 1) - tmp
y,z = (y + z + 1) - mod,mod
ans += 1
while (x > 0):
x -= 1
q = ((y - k) // (k - 1))
y -= q * (k - 1)
z += q * k
ans += q
# 整体处理
if y == k:
ans += 1
y = k + z + 1
z = 0
else:
ans += 2
y -= (k - 1)
z += k
remain = k - y
y = (y + z + 1) - remain
z = remain
# 处理边界情况
print(ans)