题目
问题描述
给定一个小于等于 1 0 9 10^9 109的正整数 n n n,此时有两种操作,
操作一:在数字 n n n的右端添加一位数字;
操作二:在数字 n n n中擦除一位数字,要保证擦除这一位数字后不会出现前导0,比如在 ′ 30 1 ′ '301' ′301′中不能擦除数字 3 3 3,否则会出现 ′ 0 3 ′ '03' ′03′,产生前导0.
问数字 n n n可以变为 2 2 2的幂所经历最少的操作数。
分析
算思维题吧,根据数据范围,所以由 n n n操作所能变为的 2 2 2的幂其实是很有限的,
反过来思考就是先求出 n n n变为某个2的幂所需要的操作数,并且从所有情况的操作数中选出一个最小的作为最终结果输出。
那么下一个问题就是如何求
n
n
n变为某个2的幂所需要的操作数。
以
150
150
150为例,求变为
1024
1024
1024所需要的操作数
设置一个量为
t
m
p
tmp
tmp,
t
m
p
tmp
tmp初始值为
0
0
0
再设置两个量
a
、
b
a、b
a、b,作为指针记录在
150
150
150跟
1024
1024
1024上所处的位置,
先第一轮比较,1与1相同,则 t m p + + tmp++ tmp++,同时 a + + 、 b + + a++、b++ a++、b++看下一位;
第二轮比较,5与0不同,这个时候直接让 a + + a++ a++,而 t m p tmp tmp与 b b b则不进行操作;
第三轮比较,0与0相同,同样 t m p + + tmp++ tmp++,同时 a + + 、 b + + a++、b++ a++、b++看下一位;
第四轮发现 a a a已经超出范围,那么结束比较。
在结果中,由 150 150 150的长度3减去 t m p tmp tmp的值就是需要进行删除操作的操作数,由 1024 1024 1024的长度减去 t m p tmp tmp的值就是需要于右端添加的操作数,两数之和就是总操作数。
最大的收获应该是了解了函数
t
o
_
s
t
r
i
n
g
to\_string
to_string,可以将数字直接转化为string
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll P2LIM = (ll)2e18;
int solve(string s, string t)
{
int tp = 0;
int sp = 0;
int taken = 0;
while (sp < s.length() && tp < t.length())
{
if(s[sp] == t[tp])
{
taken++;
tp++;
}
sp++;
}
return (int)s.length() - taken + (int)t.length() - taken;//前为删除操作数,后为添加操作数
}
vector<string> ts;
int main()
{
for (ll p2 = 1; p2 <= P2LIM; p2 *= 2)
ts.push_back(to_string(p2));
int t;
cin >> t;
while (t--)
{
string n;
cin >> n;
int ans = n.length() + 1;
for (auto p2 : ts)
ans = min(ans, solve(n, p2));
cout << ans << endl;
}
return 0;
}