这好像是出给学弟的模拟赛题
Solution
显然需要考虑 DP。观察数据范围设 \(f_i\) 表示生成一个长度为 \(i\) 的字符串所需要的最少花费。
三个操作对应着 \(i \to i - 1, i \to i + 1, i \to i \times 2\)。
如果没有中间那个操作,显然每个状态只会由前面的状态转移而来,直接转移即可,转移方程如下:
\[f_i = \min \{ f_{i-1} + X \} \] \[f_i = \min \{ f_{i/2} + Y\} (i \bmod 2 =0) \]考虑中间的操作 \(i \to i + 1\),它需要使用到后面的状态,这个状态我们现在并没有更新。那么我们想:我们能不能从 \(\frac{i+1}{2} \to i+1 \to i\),因为 \(f_{(i+1)/2}\) 我们是确定的是吧。
想了想是可以的。并且只需要在 \(i \bmod 2 = 1\) 的时候考虑这个转移即可,所以有转移方程:
\[f_{i} = \min \{ f_{(i+1)/2} + X + Y \}(i \bmod 2 = 1) \](如果 \(i \bmod 2 = 0\) 的话根本不需要 \(-1\))
把这三个转移方程结合起来这题就做完了,时间复杂度 \(\mathcal O(n)\)。
Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 1e7 + 10;
int n, X, Y;
int f[MAXN];
signed main() {
cin >> n >> X >> Y;
memset(f, 0x3f, sizeof f);
f[0] = 0;
for(int i = 1; i <= n; ++i) {
f[i] = min(f[i], f[i - 1] + X);
if(i & 1) {
f[i] = min(f[i], f[i + 1 >> 1] + X + Y);
} else {
f[i] = min(f[i], f[i >> 1] + Y);
}
}
printf("%lld\n", f[n]);
return 0;
}