两道倍数codeforces 题 —— 2倍与加减1相关


题1 https://codeforces.com/problemset/problem/520/B
题2 https://codeforces.com/problemset/problem/710/E

题目大意

题1

一个设备可支持两种操作:
将当前数 \times 2 。
将当前数 -1−1 。
另外,当设备中的数不是正数时,设备将会崩溃。
现在给出两个数 n,m ,问你需要多少次操作才能将 n 变成 m 。

题2

给定正整数 n, x, y,你要生成一个长度为 n 的字符串,有两种操作:
添一字符或删去一个原有字符,代价为 x;
将已有字串复制粘贴一次(翻倍),代价为 y。
求最小代价。

思路

题1

1,让我们先来看第一题
要让我们分类讨论。因为都是正数

  1. 所以当 n>m 时,只有n--才可以到达m。 这个时候是不可能再有n*2这个步骤的
  2. 当n<m时。n*2 与 n-- 难于判断,正难则反
    若需要将 m->n ,则说明啥,m可以除2时,就除以2,如果不能,那我就再加1,然后除2。只有这两个步骤才能到达n
    那存不存在 我先加两次1,然后再除以2,那肯定没有必要啊,这个操作数会大于 n/2 再加1 的两次操作
    明显贪心
题2

第2题,题目是:
0->n 其中inc/dec 为 x代价 =2 为 y代价
跟1题的不同点在于
1,0<n
2, 可以加1,也可以减1
跟第1题相比,明显这题是使用dp,而且很容易陷入完全背包解法。而实际上可以利用:
2可以分两种情况讨论,当i为偶数/奇数时
偶数:dp[i] = max(dp[i/2]+y,dp[i-1]+x);
奇数:dp[i] = max(dp[(i+1)/2]+x+y,dp[i-1]+x);
其它情况,代价更高,故不需要考虑。

总结

当看到 *=2, +-1 这些条件时,就需要想到通过奇偶去分别讨论。

AC代码

520/B
#include <iostream>
#include <cassert>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <cmath>
#include <climits>
#include <functional>
#include <list>
#include <cstdlib>
#include <set>
#include <stack>
#include <sstream>
#include <numeric>
#include <map>
#include <algorithm>
#include <bitset>

#define endl "\n"
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define MZ(arr) memset(arr,0,sizeof(arr))
#define MS(arr,val) memset(arr,val,sizeof(arr))

using namespace std;

#define NMAX 100005

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int n, m;
	cin >> n >> m;
	if (n >= m) {
		cout << n - m << endl;
	} else {
		int s = 0;
		while (n  < m) {
			int p1 = m & 1;
			s += 1 + p1;
			m += p1;
			m /= 2;
		}
		s += n - m;
		cout << s << endl;
	}

	return 0;
}
710/E
#include <iostream>
#include <cassert>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <cmath>
#include <climits>
#include <functional>
#include <list>
#include <cstdlib>
#include <set>
#include <stack>
#include <sstream>
#include <numeric>
#include <map>
#include <algorithm>
#include <bitset>

#define endl "\n"
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define MZ(arr) memset(arr,0,sizeof(arr))
#define MS(arr,val) memset(arr,val,sizeof(arr))

using namespace std;

#define NMAX 100005

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int n, x, y;
	cin >> n >> x >> y;
	vector<ll> dp(n + 1, LINF);
	dp[0] = 0;
	dp[1] = x;
	for (int i = 2; i <= n; ++i) {
		if (i& 1) {
			int xx = (i + 1) / 2;
			dp[i] = min(dp[xx] + x + y, dp[i - 1] + x);
		}
		else {
			dp[i] = min(dp[i / 2] + y, dp[i - 1] + x);
		}
	}
	cout << dp[n] << endl;
	return 0;
}
posted @ 2023-05-11 18:49  传说中的水牛  阅读(29)  评论(0编辑  收藏  举报