两道倍数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,让我们先来看第一题
要让我们分类讨论。因为都是正数
- 所以当 n>m 时,只有n--才可以到达m。 这个时候是不可能再有n*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;
}