LG 题解 CF710E Generate a String

这好像是出给学弟的模拟赛题

题面传送 | 更差的阅读体验?

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;
}

上一篇:欧几里得算法


下一篇:CF450B Jzzhu and Sequences 题解