# NENUOJ 之 算法1第5章
# 5001 特殊的四位数 (opens new window)
# 题目描述
找出并输出所有小于等于n的4位数(十进制数)中具有如下属性的数:四位数字之和等于其十六进制形式各位数字之和,也等于其十二进制形式各位数字之和。 例如:十进制数2991,其四位数字之和2+9+9+1 = 21。由于2991 = 1 * 1728 + 8 * 144 + 9 * 12 + 3,其十二进制形式为1893(12), 其各位数字之和也为21。但是它的十六进制形式为BAF(16),其各位数字之和等于11+10+15 = 36。因此你的程序要舍去2991这个数据。 下一个数2992,其十进制、十二进制、十六进制形式各位数字之和均为22,因此2992符合要求,应该输出来。(只考虑4位数,2992是第一个符合要求的数)
# 输入
输入有多行,每行一个正整数n(四位整数)。
# 输出
你的程序要求输出满足要求的四位数(要求严格按升序输出),每个数占一行(前后都没有空行),整个输出以换行符结尾。输出中没有空行。输出中的前几行如输出样例所示。如果没有则输出0。
# 样例输入 复制
2000 3000
# 样例输出 复制
0 2992 2993 2994 2995 2996 2997 2998 2999
# 思路:
写习惯进制转换的函数就好~算是一道比较基础的进制转换题目。
# 代码C语言:
#include<stdio.h>
int find(int n,int base){
int sum = 0;
while(n > 0){
sum += n % base;
n /= base;
}
return sum;
}
int main(){
int n;
while(~scanf("%d",&n)){
int flag = 0;
for(int i = 1000;i <= n;i++){
int sum = find(i,10);
int sum12 = find(i,12);
int sum16 = find(i,16);
if(sum == sum12 && sum == sum16){
printf("%d\n", i);
flag = 1;
}
}
if(!flag){
flag = 0;
printf("0\n");
}
}
return 0;
}
# 5002 进制转换 (opens new window)
# 题目描述
输入一个十进制数N,将它转换成R进制数输出。
# 输入
输入数据包含多个测试实例,每个测试实例包含两个整数N(32位整数)和R(2<=R<=16,R != 10)。
# 输出
为每个测试实例输出转换后的数,每个输出占一行。如果R大于10,则对应的数字规则参考16进制(比如,10用A表示,等等)。
# 样例输入 复制
7 2 23 12 -4 3
# 样例输出 复制
111 1B -11
# 思路:
十进制转R进制,首先需要有个数组存储进制值,如下方代码的temp数组一样。
然后用个while循环不断除以进制数R,就能得到序列了,最后输出即可。详情看代码~
# 代码C语言:
#include<stdio.h>
#include<string.h>
char temp[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
void jinzhi(char str[],int n,int r){
int flag = 0;
if(n < 0){
n = -n;
flag = 1;
}
int i = 0;
while(n){
str[i++] = temp[n % r];
n /= r;
}
if(flag == 1) printf("-");
for(int j = i - 1;j >= 0;j--){
printf("%c",str[j]);
}
}
int main(){
int n,r;
char str[10000];
while(~scanf("%d %d",&n,&r)){
jinzhi(str,n,r);
printf("\n");
}
return 0;
}
# 5003 skew数 (opens new window)
# 题目描述
在skew 二进制数表示中,第k位的值xk 表示xk * (2k+1-1) 。每个位上的可能数字是0或1,最后面一个非零位可以是2,例如, 10120(skew) = 1 * (25-1) + 0 * (24-1) + 1 * (23-1) + 2 * (22-1) +0 * (21-1) = 31 + 0 + 7 + 6 + 0 = 44. 前十个skew 数是 0、1、2、10、11、12、20、100、101以及102。
# 输入
输入包含一行或多行,每行包含一个整数n。如果n = 0 表示输入结束,否则n 是一个skew 数。
# 输出
对于每一个输入,输出它的十进制表示。转换成十进制后, n 不超过 231-1 = 2 147 483 647。
# 样例输入 复制
10120 200000000000000000000000000000 10 1000000000000000000000000000000 11 100 11111000001110000101101102000 0
# 样例输出 复制
44 2147483646 3 2147483647 4 7 1041110737
# 思路:
按题目意思模拟即可,一位一位处理。
# 代码C语言:
#include<stdio.h>
#include<string.h>
#include<math.h>
int main(){
char str[10000];
while(~scanf("%s",str)){
if(str[0] == '0') break;
int sum = 0;
int len = strlen(str);
for(int i = 0;i <= len - 1;i++){
sum += (str[i]-'0') * (pow(2,len - i) - 1);
}
printf("%d\n",sum);
sum = 0;
}
return 0;
}
# 5004 周易 (opens new window)
# 题目描述
有人说,中国古代的“周易”是二进制系统的起源,在该系统中,他们用“- -”表示1,“---”表示0。因此,二进制数字“011010”可以表述为“---\n- -\n- -\n---\n- -\n---\n”(符号“\n”表示换行)。现在的问题是如何把一个十进制数转换为“周易”中的二进制?
# 输入
文件中包含多组测试数据。每个测试数据占一行,包括一十进制整数n(0 <= n <= 1000000)和表示二进制位数的k(0 < k <= 20 且 n < 2k)。 n=0,k=0表示输入结束。
# 输出
对于每组测试数据,输出“周易”中对应的k行二进制数。每组测试数据之间输出一个空行。
# 样例输入 复制
7 3 0 3 26 6 0 0
# 样例输出 复制
- - - - - - --- --- --- --- - - - - --- - - ---
# 思路:
自行模拟,转换成二进制,遇到1和0输出不一样的。注意,如果k很大,2的k次方超过n,就会有一些0的出现。
# 代码C语言:
#include<stdio.h>
#include<string.h>
#include<math.h>
char str[10000];
char temp[] = {'0','1'};
int main(){
int n,k;
while(~scanf("%d %d",&n,&k)){
if(!n && !k) break;
int i = 0,j = 0;
//转二进制
while(n){
str[i++] = temp[n % 2];
n /= 2;
}
//把超过范围的那部分二进制的0输出了
if(i < k){
int len = k - i;
while(len--){
printf("---\n");
}
}
for(j = i - 1;j >= 0;j--){
if(str[j]=='1'){
printf("- -");
}
else{
printf("---");
}
printf("\n");
}
printf("\n");
}
return 0;
}
# 5005 奶牛计算器 (opens new window)
# 题目描述
由于缺乏数学经验,奶牛想建立一个计算机器(它被称为Cowmpouter),使用二进制数字(基数为2),但它是建立在-2的基础上。他们非常高兴,因为在-2进制表示的数字中不需要符号位。 你知道基数的权值都是从1开始的(0位),然后从右到左依次为基数1次方,基数2次方等等。在-2进制中,其权值从右到左,依次为1,-2,4,-8,16,-32,…。因此,从1计数依次是:1,110,111,100,101,11010,11011,11000,11001等等。 很怪异的是,负数也那个用1和0表示,但没有符号位。从-1向下计数依次为:11,10,1101,1100,1111等等。 请帮助奶牛把普通的十进制整数(范围为:-2,000,000,000到2,000,000,000)转换为-2进制对应的数。
# 输入
输入只有一行,一个需要转换为-2进制的十进制整数。
# 输出
对应的-2进制的数,没有前导0,0就表示0本身,只用1个0。
# 样例输入 复制
-13
# 样例输出 复制
110111
# 思路:
这道题的思路就是,不断除以-2,然后输出0或者1。然后简单把玩一下数据,大概就能发现奇数偶数处理上的不同,正奇数和负奇数页有所不同,所以就会得到下方代码。
# 代码C语言:
#include<stdio.h>
//转换函数
void convert(int n) {
if(n == 0) return;
//如果是偶数,尾数是0
if(n % 2 == 0) {
//除以-2,之后补0【因为从右往左】
convert(-(n / 2));
printf("0");
} else {
//如果是奇数,尾数是1
//除以-2,之后补1【因为从右往左】
if(n > 0) convert(-(n / 2));
else convert(-(n - 1) / 2);
printf("1");
}
}
int main() {
int n;
scanf("%d", &n);
if(n == 0) printf("0");
else convert(n);
printf("\n");
return 0;
}
# 5006 计算器设计 (opens new window)
# 题目描述
Really Neato计算器公司最近邀请你的团队为他们设计一款超级Neato一代计算器。作为计算机科学家,你建议该计算器能够在各种进制之间进行转换。他们认为这是一个很好的想法,并要求你的团队先给出实现进制转换的算法原型。公司经理告诉你,该计算器应该具有以下一些特征: (1)可以显示7位; (2)按键除了数字0到9外,还包括大写字母A到F; (3)支持2~16进制。
# 输入
输入文件中的每行为一个进制转换,包括3个数,第1个数是原进制下的一个整数,第2个数就是原进制,第3个数是转换后的进制。这3个数的两边可能有一个或多个空格。输入数据一直到文件结尾。
# 输出
实现所有的进制转换,转换后的数右对齐到7位显示。如果转换后的数的位数太多,超过7位,则输出“ERROR”,也是右对齐到。
# 样例输入 复制
1111000 2 10 1111000 2 16 2102101 3 10 2102101 3 15 12312 4 2 1A 15 2 1234567 10 16 ABCD 16 15
# 样例输出 复制
120 78 1765 7CA ERROR 11001 12D687 D071
# 代码C语言:
#include<stdio.h>
#include<string.h>
#include<math.h>
char temp[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char str2[10000];
int solve(char str[],int r1){
int sum = 0;
int len = strlen(str);
int i;
for(i = len-1;i >= 0;i--){
if(str[i] >= '0' && str[i] <= '9'){
sum = sum + (str[i]-'0')*pow(r1,len-i-1);
}
if(str[i] >= 'A' && str[i] <= 'F'){
sum = sum + (str[i]-55)*pow(r1,len-i-1);
}
}
return sum;
}
void solve2(int sum,int r2){
int i = 0,j = 1;
while(sum){
str2[i] = temp[sum%r2];
i++;
sum /= r2;
}
str2[i] = '\0';
int len = strlen(str2);
for(j = 1;j <= 7 - len;j++){
printf(" ");
}if(len > 7){
printf(" ERROR\n");
return;
}
for(i = len-1;i >= 0;i--){
printf("%c",str2[i]);
}
printf("\n");
}
int main(){
char str[10000];
int r1,r2;
while(~scanf("%s %d %d",str,&r1,&r2)){
solve2(solve(str,r1),r2);
}
return 0;
}
# 5007 回文数 (opens new window)
# 题目描述
如果一个数从左往右读和从右往左读都是一样的话,那么我们就称它是一个回文数。例如,75457就是一个回文数。 当然,这种性质要取决于这个数是在什么进制下。例如,17在十进制下不是一个回文数,但在二进制下(10001)则是一个回文数。 题目要求你来验证给定的数在2~16进制中的哪些进制下是否是回文数。
# 输入
输入文件包含了若干个十进制整数n,0 < n < 50000,每个整数占一行。0表示结束。
# 输出
如果整数i在某些进制下是回文数,则输出“Number i is palindrom in basis”,然后分别输出这些进制,其中i是给定的整数。如果在2~16进制下都不是回文数,则输出“Number i is not palindrom”。
# 样例输入 复制
17 19 0
# 样例输出 复制
Number 17 is palindrom in basis 2 4 16 Number 19 is not a palindrom
# 代码C语言:
#include<stdio.h>
#include<string.h>
char temp[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
void jinzhi(char str[],int n,int r){
int i = 0;
while(n){
str[i++] = temp[n%r];
n /= r;
}
}
int judge(char str[]){
int i;
int flag = 1;
int len = strlen(str);
for(i = 0;i <= len/2;i++){
if(str[i] != str[len - i - 1]){
flag = 0;
}
}
return flag;
}
void solve(int n,int i,int count){
if(count==0)
printf("Number %d is palindrom in basis",n);
printf(" %d",i);
}
int main(){
int n;
while(1){
int flag = 0;
int i;
scanf("%d",&n);
if(n==0) break;
int count = 0;
for(i = 2;i <= 16;i++){
char str[100] = {'\0'};
jinzhi(str,n,i);
flag = judge(str);
if(flag == 1){
solve(n,i,count);
count++;
}
}
//printf("flag = %d\n",flag);
if(count == 0){
printf("Number %d is not a palindrom",n);
}
printf("\n");
}
return 0;
}
# 5101 十进制转换八进制 (opens new window)
# 题目描述
把一个十进制正整数转化成八进制。
# 输入
若干行,每行仅含一个十进制表示的正整数a(0 < a < 65536)。
# 输出
针对输入的每一行输出a的八进制表示。
# 样例输入 复制
9 8
# 样例输出 复制
11 10
# 代码C语言:
#include<stdio.h>
char num[] = {'0','1','2','3','4','5','6','7'};
int main(){
int a;
char str[10000];
while(~scanf("%d",&a)){
int temp = a;
int i = 0,j;
while(temp){
str[i] = num[(temp%8)];
temp /= 8;
i++;
}
for(j = i - 1; j >= 0;j--){
printf("%c",str[j]);
}
printf("\n");
}
return 0;
}
# 5102 Sky数 (opens new window)
# 题目描述
Sky从小喜欢奇特的东西,而且天生对数字特别敏感,一次偶然的机会,他发现了一个有趣的四位数2992,这个数,它的十进制数表示,其四位数字之和为2+9+9+2=22,它的十六进制数BB0,其四位数字之和也为22,同时它的十二进制数表示1894,其四位数字之和也为22,啊哈,真是巧啊。Sky非常喜欢这种四位数,由于他的发现,所以这里我们命名其为Sky数。但是要判断这样的数还是有点麻烦啊,那么现在请你帮忙来判断任何一个十进制的四位数,是不是Sky数吧。
# 输入
输入包括多个四位正整数,如果为0,则输入结束。
# 输出
若n为Sky数,则输出“#n is a Sky Number.”,否则输出“#n is not a Sky Number.”。每个结果占一行。注意:#n表示所读入的n值。
# 样例输入 复制
2992 1234 0
# 样例输出 复制
2992 is a Sky Number. 1234 is not a Sky Number.
# 代码C语言:
#include<stdio.h>
int main(){
int num;
while(~scanf("%d",&num)){
if(num == 0) break;
int sum10 = 0;
int sum16 = 0;
int sum12 = 0;
int temp = num;
int i,j;
while(temp){
sum10 += temp%10;
temp /= 10;
}
temp = num;
while(temp){
sum16 += temp%16;
temp /= 16;
}
temp = num;
while(temp){
sum12 += temp%12;
temp /= 12;
}
if(sum10 == sum12 && sum10==sum16){
printf("%d is a Sky Number.\n",num);
}
else{
printf("%d is not a Sky Number.\n",num);
}
}
return 0;
}
# 5111八进制转换十进制 (opens new window)
# 题目描述
把一个八进制正整数转化成十进制。
# 输入
输入有多行,每行仅含一个八进制表示的正整数a,a的十进制表示的范围是(0 < a < 65536)。
# 输出
一行,a的十进制表示。
# 样例输入 复制
11 10
# 样例输出 复制
9 8
# 代码C语言:
#include<stdio.h>
#include<string.h>
char str[10000];
int main(){
while(~scanf("%s",str)){
int sum = 0;
int i = strlen(str);
sum = 0;
for(int j = 0;j < i;j++){
sum = sum * 8 + (str[j]-'0');
}
printf("%d\n",sum);
}
return 0;
}
# 5112确定进制 (opens new window)
# 题目描述
6 * 9 = 42 对于十进制来说是错误的,但是对于13进制来说是正确的。即, 6(13) * 9(13) = 42(13), 而 42(13) = 4 * 13^1 + 2* 13^0 = 54(10)。 你的任务是写一段程序读入三个整数p、q和r,然后确定一个进制B(2 <= B <= 16) 使得 p * q = r。如果 B有很多选择,输出最小的一个。例如:p = 11,q = 11,r = 121。则有 11(3) * 11(3) = 121(3) 因为 11(3) = 1 * 3^1 + 1 * 3^0 = 4(10) 和 121(3) = 1 * 3^2 + 2 * 3^1 + 1 * 3^0 = 16(10)。 对于进制10。有 11(10) * 11(10) = 121(10)。这种情况下,应该输出3。如果没有合适的进制,则输出0。
# 输入
输入有T组测试样例。 T在第一行给出。每一组测试样例占一行,包含三个整数p、q、r。p、q、r的所有位都是数字,并且1 <= p、q、r <= 1,000,000。
# 输出
对于每个测试输出样例一行。该行包含一个整数:即使得p * q = r成立的最小的B。如果没有合适的B,则输出 0。
# 样例输入 复制
3 6 9 42 11 11 121 2 2 2
# 样例输出 复制
13 3 0
# 代码C语言:
#include<stdio.h>
#include<string.h>
#include<math.h>
int main(){
int t;
scanf("%d",&t);
char p[1000];
char q[1000];
char r[1000];
int i,j,k,l;
while(t--){
scanf("%s %s %s",p,q,r);
int len = strlen(r);
int len1 = strlen(p);
int len2 = strlen(q);
for(i = 2;i <= 16;i++){
long long sum = 0;
long long sum1 = 0;
long long sum2 = 0;
for(k = len1-1; k >= 0;k--){
sum1 += (p[k] - '0') * pow(i,len1 - k - 1);
if((p[k] - '0') >= i) {
l = -3;
k = -3;
j = -3;
break;
}
}
for(l = len2-1; l >= 0;l--){
sum2 += (q[l] - '0') * pow(i,len2 - l - 1);
if((q[l] - '0') >= i) {
l = -3;
k = -3;
j = -3;
break;
}
}
for(j = len-1;j >= 0;j--){
sum += (r[j] - '0') * pow(i,len - j - 1);
if((r[j] - '0') >= i) {
l = -3;
k = -3;
j = -3;
break;
}
}
if(sum == sum1 * sum2 && l == -1 && j == -1 && k == -1){
printf("%d\n",i);
i = 17;
}
if(i == 16){
printf("0\n");
}
}
}
return 0;
}
# 5201 二进制位 (opens new window)
# 题目描述
给定你一个十进制数n(0 < n < 1000),要求输出其二进制数。
# 输入
输入有多行,每行包括一个十进制的正整数n。
# 输出
输出对应的二进制数。
# 样例输入 复制
1 2 3
# 样例输出 复制
1 10 11
# 代码C语言:
#include<stdio.h>
int main(){
int n;
while(~scanf("%d",&n)){
int str[1005] = {0};
int i = 0;
while(n){
str[i++] = n % 2;
n /= 2;
}
for(int j = i - 1;j >= 0;j--){
printf("%d",str[j]);
}
printf("\n");
}
}
# 5202 二进制转化为十六进制 (opens new window)
# 题目描述
输入一个2进制的数,要求输出该2进制数的16进制表示。在16进制的表示中,A-F表示10-15。
# 输入
第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个以0和1组成的字符串,字符串长度至少是1,至多是10000。
# 输出
n行,每行输出对应一个输入。
# 样例输入 复制
2 100000 111
# 样例输出 复制
20 7
# 代码C语言:
#include<stdio.h>
#include<string.h>
#include<math.h>
char str2[10005];
int j = 0;
char temp[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G'};
void jinzhi(char str[]){
int i;
int len = strlen(str);
int count = 0;
int sum = 0;
j = 0;
for(i = len - 1;i >= 0;i--){
sum += (int)((str[i] - '0') * pow(2,count));
count++;
if(count % 4 == 0){
count = 0;
str2[j++] = temp[sum];
sum = 0;
}
}
if(count!=0){
str2[j++] = temp[sum];
}
}
int main(){
int n;
int i = 0;
scanf("%d",&n);
while(n--){
char str[10005] = {'\0'};
scanf("%s",str);
jinzhi(str);
for(i = j - 1;i >= 0;i--){
printf("%c",str2[i]);
}
printf("\n");
}
return 0;
}
# 5203 周易II (opens new window)
# 题目描述
有人说,中国古代的“周易”是二进制系统的起源,在该系统中,他们用“- -”表示1,“---”表示0。因此,二进制数字“011010”可以表述为“---\n- -\n- -\n---\n- -\n---\n”(符号“\n”表示换行)。现在的问题是如何把一个“周易”中的二进制转换为相应的十进制数?
# 输入
文件中包含多组测试数据。每个测试数据都是以一个数字k (0 < k <= 20)开始,表示这个数在二进制中的位数。接下来就是k行,就是字符串---或- -,第1位表示最高位。
# 输出
对于每组测试数据,输出对应的十进制数。
# 样例输入 复制
3 - - - - - - 3 --- --- --- 6 --- - - - - --- - - ---
# 样例输出 复制
7 0 26
# 思考:
这道题有脏数据【确信】而且还有Linux系统很诡异的换行问题。
所以笔者推荐每一行都用fgets把换行符给读入了,不然可能产生不知名的错误。
# 代码C语言 代码一:
#include<stdio.h>
#include<string.h>
int main(){
char str[1000][1000];
int n;
int i;
char res[1000];
while(~scanf("%d",&n)){
int j = 0;
getchar();
getchar();
for(i = 0;i < n;i++){
gets(str[i]);
if(strncmp(str[i],"- -",3)==0){
res[j++] = '1';
}
if(strncmp(str[i],"---",3)==0){
res[j++] = '0';
}
}//011010
long long sum = 0;
for(i = 0;i < j;i++){
sum = sum * 2 + (res[i]-'0');
}
printf("%lld\n",sum);
}
return 0;
}
# 代码C语言 代码二:
#include<stdio.h>
#include<string.h>
int str[10000];
long long solve(int n){
long long sum = 0;
for(int j = n;j >= 1;j--){
sum += str[j] * pow(2,n - j);
}
return sum;
}
int main()
{
char first[1000] = {'\0'};
while(fgets(first,sizeof(first),stdin)){
int k = first[0] - '0';
for(int i = 1;i <= k;i++){
char temp[1000] = {'\0'};
fgets(temp,sizeof(temp),stdin);
str[i] = temp[1] == '-' ? 0 : 1;
}
printf("%lld\n",solve(k));
}
return 0;
}
# 5204 二进制数 (opens new window)
# 题目描述
给定一个正整数n,要求输出对应的二进制数中所有数码“1”的位置。注意最低位为第0位。例如13的二进制形式为1101,因此数码1的位置为:0,2,3。
# 输入
输入文件中的第1行为一个正整数d,表示输入文件中测试数据的个数,1<=d<=10,接下来有d个测试数据。每个测试数据占一行,只有一个整数n,1<=n<= 106。
# 输出
输出包括d行,即对输入文件中的每个测试数据,输出一行。第i行,1 <= i <= d,以升序的顺序输出第i个测试数据中的整数的二进制形式中所有数码1的位置,位置之间有1个空格,最后一个位置后面没有空格。
# 样例输入 复制
2 13 127
# 样例输出 复制
0 2 3 0 1 2 3 4 5 6
# 代码C语言 代码一:
#include<stdio.h>
#include<string.h>
#include<math.h>
char str[10000];
char temp[] = {'0','1'};
int main(){
int d;
scanf("%d",&d);
while(d--){
int n;
scanf("%d",&n);
int i = 0,j = 0;
while(n){
str[i++] = temp[n%2];
n /= 2;
}
for(j = 0;j < i;j++){
if(str[j]=='1'){
printf("%d ",j);
}
}
printf("\n");
}
return 0;
}
# 代码C语言 代码二:
#include <stdio.h>
int main() {
int d;
scanf("%d", &d);
while(d--) {
int n;
scanf("%d",&n);
int first = 1;
for(int i = 0;i < 31;i++){
if((n & (1 << i)) != 0) {
if(first){
printf("%d", i);
first = 0;
}else{
printf(" %d", i);
}
}
}
printf("\n");
}
return 0;
}
# 5205 留下最少 (opens new window)
# 题目描述
给定一个基数b,和b进制下的两个非负整数p和m,计算p%m,并输出b进制下的结果。p%m的结果被定义为非负整数k,要求k是满足p=a * m + k中的最小值(a为某些整数)。
# 输入
输入包含多组测试数据。每个测试数据占一行,由3个无符号的整数构成,第一个整数为b,一个介于2到10之间的十进制数。第二个为p,可能由1000位的0到b-1构成。第三位是m,由9位0到b-1构成。 最后一个测试数据为0,表示输入结束。
# 输出
对应每组测试数据,要求输出一行b进制下的p%m。
# 样例输入 复制
2 1100 101 10 123456789123456789123456789 1000 0
# 样例输出 复制
10 789
# 思路:
一个任意进制的数,对x取余的结果 等于 其各个数位上的数对x取余的结果的和 再对x取余。
即 对于任何整数 $a$, $b$, $m$,我们有 $(a + b) % m = ((a % m) + (b % m)) % m$
比如 $123456789$,即 $110^8 + 210^7 + 310^6 + 410^5 + 510^4 + 610^3 + 710^2 + 810^1 + 9*10^0$
$(1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9) % 10 = 45 % 10 = 5$。
所以这道题我们求的虽然是$p % m$,实际上就是:如果一个数$p$在任意进制下表示为$d_1d_2d_3...d_n$,那么$p%m = ((d_1%m) + (d_2%m) + ... + (d_n%m)) % m$
然后具体请看代码~
# 代码C语言:
#include<stdio.h>
#include<string.h>
int main(){
int b;
char p[1005], m[10];
while(scanf("%d", &b) != EOF && b) {
scanf("%s %s",p,m);
long long mx = 0;
int len_m = strlen(m);
//求m的值
for(int i = 0;i < len_m;i++)
mx = mx * b + m[i] - '0';
long long px = 0;
int len_p = strlen(p);
//用模运算求p的值
for(int i = 0; i < len_p; i++){
px = px * b + p[i] - '0';
px %= mx;
}
//特判0
if(px == 0)
printf("0\n");
else{
char ans[1005];
int len = 0;
//进制转换成b进制
while(px > 0){
ans[len++] = px % b + '0';
px /= b;
}
for(int i = len - 1;i >= 0;i--)
printf("%c", ans[i]);
printf("\n");
}
}
return 0;
}
# 5206 进制转换 (opens new window)
# 题目描述
编写程序,实现将一个数从一种进制转换到另一种进制。在这些进制中,可以出现的数码有62个:{0-9,A-Z,a-z}。
# 输入
输入文件的第1行是一个正整数N,表示测试数据的个数,接下来有N行,每行的格式为:输入数据的进制(用十进制表示),输出数据的进制(用十进制表示),最后一个是用输入数据的进制所表示的数。输入/输出数据的进制范围是2 ~ 62,也就是说A ~ Z相当于十进制中的10 ~ 35,a ~ z相当于十进制中的36 ~ 61。
# 输出
对每个测试数据,程序输出3行,第1行是输入数据的进制,空格,然后是在该进制下的输入数据;第2行是输出数据的进制,空格,然后是在该进制下的输出数据;第3行为空行。
# 样例输入 复制
8 62 2 abcdefghiz 10 16 1234567890123456789012345678901234567890 16 35 3A0C92075C0DBF3B8ACBC5F96CE3F0AD2 35 23 333YMHOUE8JPLT7OX6K9FYCQ8A 23 49 946B9AA02MI37E3D3MMJ4G7BL2F05 49 61 1VbDkSIMJL3JjRgAdlUfcaWj 61 5 dl9MDSWqwHjDnToKcsWE1S 5 10 42104444441001414401221302402201233340311104212022133030
# 样例输出 复制
62 abcdefghiz 2 11011100000100010111110010010110011111001001100011010010001 10 1234567890123456789012345678901234567890 16 3A0C92075C0DBF3B8ACBC5F96CE3F0AD2 16 3A0C92075C0DBF3B8ACBC5F96CE3F0AD2 35 333YMHOUE8JPLT7OX6K9FYCQ8A 35 333YMHOUE8JPLT7OX6K9FYCQ8A 23 946B9AA02MI37E3D3MMJ4G7BL2F05 23 946B9AA02MI37E3D3MMJ4G7BL2F05 49 1VbDkSIMJL3JjRgAdlUfcaWj 49 1VbDkSIMJL3JjRgAdlUfcaWj 61 dl9MDSWqwHjDnToKcsWE1S 61 dl9MDSWqwHjDnToKcsWE1S 5 42104444441001414401221302402201233340311104212022133030 5 42104444441001414401221302402201233340311104212022133030 10 1234567890123456789012345678901234567890
# 代码C语言:
#include <stdio.h>
#include <string.h>
int main() {
int t;
scanf("%d", &t);
while(t--){
int a, b;
char c[100],d[100];
scanf("%d %d %s",&a,&b,c);
int arr[100] = {0},res[100] = {0};
int arr_size = 0;
int len_c = strlen(c);
for(int i = len_c - 1;i >=0;i--){//反转得到数组
if(c[i] >='0' && c[i] <='9') arr[arr_size++] = c[i] - '0';
if(c[i] >='A' && c[i] <='Z') arr[arr_size++] = c[i] - 'A' + 10;
if(c[i] >='a' && c[i] <= 'z') arr[arr_size++] = c[i] - 'a' + 36;
}
int res_size = 0;
while(arr_size){
int r = 0;
//进制转换
for(int i = arr_size - 1;i >=0;i--){
arr[i] += r * a;
r = arr[i] % b;
arr[i] /= b;
}
res[res_size++] = r;//每次将余数加入到数组中
while(arr_size && arr[arr_size - 1] == 0) arr_size--;//去除前导0
}
int d_index = 0;
//把数字转换成进制的字符
for(int i = res_size - 1;i >= 0;i--){
if(res[i] >= 0 && res[i] <= 9) d[d_index++] = res[i] + '0';
if(res[i] >= 10 && res[i] <= 35) d[d_index++] = res[i] + 'A' - 10;
if(res[i] >= 36) d[d_index++] = res[i] + 'a' - 36;
}
d[d_index] = '\0';
printf("%d %s\n",a,c);
printf("%d %s\n\n",b,d);
}
return 0;
}
# 总结
- 这套题都是进制转换,大多数题目考察的内容都是一致的,本质上就是进制转换,善用短除法处理,把余数存储,就可以得到不同的进制。
- 部分题目会涉及到字符串的使用,还有像周易Ⅱ该题会出现字符处理的情况,需要用fgets整行读入为好。