原题链接:
题意:
- 输入t个整数n,每个整数可以进行两种操作:1.任意删除数字 或者2.在最右方添加一个数字。
- 要使最终得到的数字是2的任意次幂,问最少操作几次。
题解:
- 考虑到增长的速度极快,而n <= 1e9,我们可以把都列出来。至于其范围为什么是到2e18,是因为要是真的要达到了接近2e18的那个数,很明显操作次数就大于了直接删除整个n数字再补一个零的操作次数了。
- 如何进行逐位比较?很显然用字符串比用整数类型的数组方便,那么在一开始就用一个变长数组,把压入此数组中。接着看到solve函数里面我的注释,进行逐位比较。
- 我们刚刚只是让n对一个进行比对,要想对所有符合条件的进行比较并且找出最小的一个数,就要用一个迭代器,把一次次地交给solve去解决。再一次次地比较哪种方案所需的操作次数最少,最终输出答案。
实现:
代码如下
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll P2LIM = (ll)2e18; int solve(string s, string t) { int sp = 0; int tp = 0; int same = 0; while(sp < s.length() && tp < t.length()) { // 如果有位数相同,那就看看下一位是否也相同 if(s[sp] == t[tp]) { same++; tp++; } //如果这位不同了,我们就绕过他看看,一直直到找到两个位数相同的再进入if() sp++; } // 最后看看要删几个数,再加上要添几个数 return (int)s.length() - same + (int)t.length() - same; } vector<string>temp; int main() { // 把2的倍数一个个列出来,并且转换为字符类型存在数组内 for(ll p2 = 1;p2 < P2LIM;p2 *= 2) temp.push_back(to_string(p2)); int t; cin >> t; while(t--) { string n; cin >> n; // 修改次数最多的情况就是全都删除再补一个1了 int ans = n.length() + 1; for(auto p2 : temp) // 对于输入的数字n与2的倍数逐位比较,得到最小的那个数 ans = min(ans,solve(n, p2)); cout << ans << endl; } return 0; }
本题收获:
- to_string()函数用法
- 迭代器的使用方法