C语言算法入门【码蹄集进阶塔】MT2181永恒之2——进位制
题目描述
小码哥被困扰住了,因为电脑它又双妤双坏了!!! 现在还是想让你算一些东西:给出一个十六进制数k,求出在1到k中“2"出现了多少次(1到k都用十六进制表示),其中k在十六进制下不大于10位。 输出的答案请对99999989取余。
输入格式:
输入格式:
第一行一个十进制整数n(1 ≤ n ≤ 10),表示k的位数。
第二行一个十六进制数k。
.
输出格式: 一个十进制整数,表示1到k中“2”出现的次数对99999989取余的答案。
样例
输入:
2
2A
.
输出: 14
备注:
首先将从1到2A的所有数全部以十六进制的方式列出来:
1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F,20,21,22,23,24,25,26,27,28,29,2A。
我们可以数得“2”一共出现了14次。
MT2181这道题主要是考验数学思维进位制
题目中是16进制,我们先按照10进制举例
还有一个特殊情况需要说明
当遍历到这个数的首位和末位时,前缀或者后缀都为0,所以要在每次循环遍历之前要对pre和suf进行初始化
对于16进制和10进制思维完全相同,主要是控制好前缀pre和后缀suf的进位关系就好了
到此,这个题的核心思想我们就讲完了,以下是代码和核心代码块的解释。
参考代码
#include <stdio.h>
#include <string.h>
#define int long long
int p[15] = {1}, a[15], n, ans;
char s[15];
const int mod = 99999989;
int main() {
scanf("%lld %s", &n, s); // 使用%lld读取long long类型,%s读取字符串
for (int i = 1; i <= n; i++)
p[i] = p[i - 1] * 16;
for (int i = 0; i < n; i++) {
if (s[i] >= '0' && s[i] <= '9')
a[i] = s[i] - '0';
else
a[i] = s[i] - 'A' + 10;
}
for (int i = 0; i < n; i++) {
int pre = 0, suf = 0;
for (int j = 0; j <= i - 1; j++)
pre = (pre * 16 + a[j]) % mod; // 确保结果在模数范围内
for (int j = i + 1; j < n; j++)
suf = (suf * 16 + a[j]) % mod; // 确保结果在模数范围内
if (a[i] > 2)
ans = (ans + (pre + 1) * p[n - i - 1] % mod) % mod;
else if (a[i] < 2)
ans = (ans + pre * p[n - i - 1] % mod) % mod;
else
ans = (ans + suf + 1 + pre * p[n - i - 1] % mod) % mod;
}
printf("%lld\n", ans); // 使用%lld打印long long类型
return 0;
}
代码块解释
for (int i = 1; i <= n; i++)
p[i] = p[i - 1] * 16;
- 这是一个循环,用于计算16的幂次,并存储在
p
数组中。p[0]
已经初始化为1,所以从p[1]
开始计算。
for (int i = 0; i < n; i++) {
if (s[i] >= '0' && s[i] <= '9')
a[i] = s[i] - '0';
else
a[i] = s[i] - 'A' + 10;
}
- 这个循环将输入的十六进制字符串
s
转换为对应的整数值数组a
。如果字符是 ‘0’ 到 ‘9’,则直接减去 ‘0’;如果是 ‘A’ 到 ‘F’,则减去 ‘A’ 并加上10。
for (int i = 0; i < n; i++) {
int pre = 0, suf = 0;
for (int j = 0; j <= i - 1; j++)
pre = (pre * 16 + a[j]) % mod; // 确保结果在模数范围内
for (int j = i + 1; j < n; j++)
suf = (suf * 16 + a[j]) % mod; // 确保结果在模数范围内
if (a[i] > 2)
ans = (ans + (pre + 1) * p[n - i - 1] % mod) % mod;
else if (a[i] < 2)
ans = (ans + pre * p[n - i - 1] % mod) % mod;
else
ans = (ans + suf + 1 + pre * p[n - i - 1] % mod) % mod;
}
-
这个循环遍历每位字符,并计算前缀
pre
和后缀suf
的十六进制值。pre
是从字符串开始到当前字符之前的十六进制值,suf
是从当前字符之后到字符串结束的十六进制值。 -
根据当前字符的值,更新
ans
。如果当前字符的值大于2,则将pre
加1后乘以p[n - i - 1]
并取模;如果小于2,则直接将pre
乘以p[n - i - 1]
并取模;如果等于2,则将suf
加1后加上pre
乘以p[n - i - 1]
并取模。
printf("%lld\n", ans); // 使用%lld打印long long类型
return 0;
printf("%lld\n", ans);
:使用printf
函数打印最终计算的结果ans
。