Link
思维 + 暴力 虽然很暴力但是很巧妙
题意
初始 P = 0 P=0 P=0, 你可以进行以下3种操作任意次,使得 P = N P = N P=N。
- 将 P + 1 P+1 P+1,花费 X X X
- 将 P + A P+A P+A,花费 Y Y Y
- 将 P + B P+B P+B,花费 Z Z Z
求最小花费。 ( 1 ≤ N , A , B , X , Y , Z ≤ 1 e 9 ) (1\leq N,A,B,X,Y,Z \leq 1e9) (1≤N,A,B,X,Y,Z≤1e9)
思路
首先令 y = min(y, a*x), z = min(z, b*x)
说一下官方解法:
令
Y
A
≤
Z
B
\frac{Y}{A} \leq \frac{Z}{B}
AY≤BZ, 显然操作2最多进行
N
A
\frac{N}{A}
AN 次,操作3最多进行
A
−
1
A-1
A−1 次,因为若操作3进行了
A
A
A 次,则它可以由
B
B
B 次操作2来代替,后者花费更少。
因为
m
i
n
(
N
A
,
A
−
1
)
≤
N
min(\frac{N}{A},A-1) \leq \sqrt N
min(AN,A−1)≤N,所以只要枚举小的那一个,并贪心地进行另一个操作,最后剩下的由操作1补全,即可得到最小花费
时间复杂度:
O
(
N
)
O(\sqrt N)
O(N)
本人并不是这么做的,但不会证明做法2333,
假设
a
<
b
a < b
a<b ,
- 令
t = max(n / (a * b) - 1, 0)
,则对于 n n n 中 t × a × b t\times a\times b t×a×b 这一部分,对花费的贡献是min(y*b, z*a) * t
。注意这个地方要-1。 - 令
n -= t * a * b
,接下来计算剩余这部分的最小花费,考虑枚举操作3的执行次数,然后对再剩余的部分尽可能多执行操作2,最后剩余的部分执行操作1,对于每次枚举取最小值即可得到最小花费。
关于时间复杂度:
时间复杂度为步骤2中操作3的执行次数,也就是
n
b
\frac{n}{b}
bn,其中
b
=
m
a
x
(
a
,
b
)
,
n
=
n
−
(
n
a
b
−
1
)
a
b
=
n
−
(
m
a
x
(
n
−
a
b
,
0
)
)
b = max(a, b),n = n - (\frac{n}{ab} - 1)ab = n - (max(n-ab, 0))
b=max(a,b),n=n−(abn−1)ab=n−(max(n−ab,0)),当
b
=
n
b = \sqrt n
b=n 的时候,
n
b
\frac{n}{b}
bn 取到最大值
n
\sqrt n
n, 即时间复杂度为
O
(
n
)
O(\sqrt n)
O(n)。
代码
void solve() {
ll n, a, b, x, y, z;
cin >> n >> a >> b >> x >> y >> z;
chmin(y, a * x);
chmin(z, b * x);
if(a > b) {
swap(a, b);
swap(y, z);
}
ll t = n / (a * b) - 1;
chmax(t, 0);
n -= t * a * b;
ll ans = min(y*b, z*a) * t;
ll delta = INF;
for(int i = 0; i * b <= n; i++) {
ll j = (n-i*b) / a;
chmin(delta, i*z+j*y+((n-i*b)%a)*x);
}
cout << ans + delta << endl;
}