luogu P13729 【MGVOI R1-A】超级奇数(odd)
题意
对于一个数,求将其转化为在十进制下所有位上是奇数所需要的最小代价。
思路
首先看样例,这种题我习惯先看样例来判断自己最初的想法,并且来向下做。
其实我第一眼看到这题是想在遇到某一位是偶数时将这一位 \(+1\)。但是看到样例后就放弃了这种做法,可见样例在这种题有多重要。
看第一组样例
input:
3
7
16
23
output:
0
1
8
发现,对于第二个数,它到最小的超级奇数只进行了 \(+1\) 操作。这并不难模拟。
但是,对于第三个数,它到最小奇数却不是我刚开始所说的遇到偶数就 \(+1\),而是 \(+8\),也就是说,我们刚开始的猜测是错误的。
那么我们重新观察第三个数,可见,\(23 + 8 = 31\)。这时候我就有个猜想,是否是遇到偶数,就将其后面每一位的数全部变成 \(1\),假设这位的数字是 \(a\),则它自己变成 \(a + 1\)。那么求最小花费就相当于求位数能到这一位数的且每一位全部为 \(1\) 的数与这位前面每一位所形成的数的差。如这个样例就相当于 \(11 - 3 = 8\)。
因为时间明显不足我们证明,所以考虑观察第二组样例进行判断。
input:
8
2
82
128
136
13365
139454
310111
975319
output:
1
9
3
1
6
57
1000
0
只看第二个和第三个数,经过转换,明显符合之前的猜测。所以就可以开始写代码了(^^)!
代码
很明显,对于每一个输入的 \(a\),进行拆位,如果遇到了一位是偶数,就将 \(ans\) 赋成前面所说的式子,至于每一位都是 \(1\) 的数,则可以进行预处理。
因为我使用了快速幂,所以总时间复杂度应约为 \(O(t \log\log a)\)
std
#include<bits/stdc++.h>
using namespace std;
int t;
long long l1[13];
long long qpow(long long x, long long y)
{
long long res = 1;
while(y)
{
if(y & 1) res *= x;
x *= x;
y >>= 1;
}
return res;
}
long long solve(long long a)
{
long long res = 0,i = 0,ans = 0;
while(a)//拆位
{
if(((a % 10) & 1) == 0) ans = l1[i + 1] - res;//如果是偶数,就直接赋值,这样 ans 就能直接到最高位的
//因为 i 是从 0 开始的,所以要 +1
res = res + (a % 10) * qpow(10,i);//求算上这位所组成的数
//因为我是从后向前判断的,如果求直接res则会有所偏差,所以这里使用了快速幂直接加
i ++;//加位数
a /= 10;//判断下一位
}
return ans ;//返回
}
int main()
{
// freopen("odd5.in","r",stdin);
// freopen("out.ans","w",stdout);
ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
cin >> t;
for(int i = 1;i <= 12;i ++) l1[i] = l1[i - 1] * 10 + 1;//预处理每一位都是 1 的数
while(t --)
{
long long a,b;cin >> a;//输入a
b = solve(a);//求代价 即b
cout << b << '\n';//输出
}
return 0;
}

浙公网安备 33010602011771号