1. 程式人生 > 其它 >LG 題解 CF710E Generate a String

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