第4章数学问题
一 %运算符
以 a % b 语句为例,我们先不加说明的指出该运算的特点。其运算在行为上好像是按如下步骤进行的,首先计算出a的绝对值被b的绝对值除所得的余数,再使该余数的符号与a保持一致。即若a为正数,则该表达式结果必为非负数(可能为0);若a为负数,则表达式结果必为非正数(可能为0)。而表达式结果与
b 的符号没有直接关系,即 a % -b与a % b的结果相同。
常用方法如下:
(a * b)%c ==(a%c * b%c)%c;
(a + b)%c ==(a%c++ b%c)%c;
((a - b)%c +c)%c
二 数位拆解
数位拆解即把一个给定的数字(如 3241)各个数位上的数字拆开,对10整取或取余等,分离各个位数即可。
/***输入a,b,对他们数位分解后,做特殊乘法,如123*45=1*4+1*5+2*4+2*5+3*4+3*5*******/
/***1,数位分解后,保存到整型数组,再相乘处理;2,直接输入到字符数组,再相乘******/
#include <iostream>
using namespace std; //int范围:-2147483648---2147483647,因此int最大长度为10,故大精度整数中可设置一个int单位保存十个位数
/*
int main(){
int a, b;
while(cin >> a >> b){
int ans1[11], ans2[11];
memset(ans1, 0, sizeof(ans1)); //对数组初始化,整型数组中的值不全为0
memset(ans2, 0, sizeof(ans2));
int size1 = 0, size2 = 0;;
do{
ans1[size1++] = a%10;
a /= 10;
}while(a);
do{
ans2[size2++] = b%10;
b /= 10;
}while(b);
int sum = 0;
int i, j;
for(i = 0; ans1[i]; i++)
for(j = 0; ans2[j]; j++)
sum += ans1[i]*ans2[j];
cout << sum <<endl;
}
return 0;
}
*/
int main(){
char a[11], b[11];
while(cin >> a >> b){
int i, j, sum = 0;
for(i = 0; i < strlen(a); i++)
for(j = 0; j < strlen(b); j++)
sum += (a[i]-'0')*(b[j]-'0');
cout << sum << endl;
}
return 0;
}</span>
3,进制转换
若题目要求整数比较大,则可用long long定义。
从 m 进制转换到 n 进制:1.从 m 进制转换到十进制;2.再从十进制转换到 n 进制。
对某进制数最开始取余得到的数为个位数,若将依次取余的数分别保存到整型数组的下标0,下标1......处,因此输出时需要逆序输出才能保证先输出的为最高位。如十进制数12356,保存在数组中,下标0-下标4:6 5 3 2 1,逆序输出为12356。
具体实现见代码:a+b.cpp和decimaltrans.cpp。
/***a+b.cpp:</span>输入m进制,和十进制long long a, b,输出m进制a+b。输入0时结束输入*******/
/***先保存十进制c=a+b,对c进行m进制分解每位数,保存到数组中,对数组反向输出*************/
#include <iostream>
using namespace std;
int main(){
long long a, b, c; //long long占64B
int m;
char ans[110];
while(cin >> m >> a >> b && m != 0){
c = a + b;
int i = 0, j;
do{
int tmp = c % m;
ans[i++] = tmp > 10 ? 'a'+tmp-10:'0'+tmp;
c /= m;
}while(c);
for(j = i-1; j >= 0; j--)
cout << ans[j]; //输出过多,可能是由于写成了死循环,如此处写成了j++
//cout << 1 << '1' << endl;
cout << endl;
}
return 0;
}
/***decimaltrans.cpp:输入进制a, a进制数n, 转换进制b,输出对应的b进制数,输出以大写字母******/
/***先将n转换为十进制,这需要n加权累加;之后并可用数组保存各位数并逆序输出********/
#include <iostream>
using namespace std;
int main(){
int a, b;
char str[110];
char ans[110];
while(cin >> a >> str >> b && a != 0){//判断时别以str[i]<=‘9’,而是以str[i] <= ‘9’判断
int i, j, q = 1;
long sum = 0;
for(i = strlen(str)-1; i >= 0; i--){
int tmp;
if(str[i] >= '0' && str[i] <= '9') tmp = str[i] - '0';
else if(str[i] <= 'z' && str[i] >= 'a') tmp = str[i] - 'a' + 10;
else tmp = str[i] - 'A' + 10;
sum += q*tmp;
q *= a;
}
//cout << sum;
i = 0;
do{
int temp = sum % b;
ans[i++] = temp > 10? 'A'+temp-10 : '0'+temp;
sum /= b;
}while(sum);
for(j = i - 1; j >= 0; j--){
cout << ans[j]; //j别输错
}
cout << endl;
}
return 0;
}
4,最大公约数
若a,b全为0,则他们的最大公约数不存在;若其中一个为0,则为非零的那一个数;若都不为0,则令a = b, b = a % b直到其中一个为0。
/***输入两个正整数,输出最大公约数******/
/***1,非递归形式;2,递归形式。a = b, b = a % b*********/
#include <iostream>
using namespace std;
int gcd(int a, int b){
if(a == 0 && b == 0) return -1;
while(b){
int tmp = a;
a = b;
b = tmp % b;
}
return a;
}
int gcd1(int a, int b){
if(a == 0 && b == 0) return -1;
if(b == 0) return a;
else return gcd1(b, a%b);
}
int main(){
int a, b;
while(cin >> a >> b)
cout << gcd1(a, b) << endl;
//cout << gcd(a, b) << endl;
return 0;
}
5,最大公倍数:(a*b)/gcd(a,b)
a、b 两数的最小公倍数为两数的乘积除以它们的最大公约数
/***给定两个正整数,计算这两个数的最小公倍数*******/
/***lcm = a*b/gcd******/
#include <iostream>
using namespace std;
int gcd(int a, int b){
if(b == 0) return a;
else return gcd(b, a%b);
}
int main(){
int a, b;
while(cin >> a >> b){
if(a == 0 && b == 0) return -1;
cout << a*b/gcd(a, b) << endl;
}
return 0;
}
六 素数筛法
确定素数(又叫质数)。素数即只能被自身和 1 整除的大于 1 的正整数,以2开始。
/***给定一个数 n,要求判断其是否为素数(0,1,负数都是非素数)*******/
/***输入一个数后,对其进行judge函数判断,即只能被1和自身整除,则为素数*****/
#include <iostream>
using namespace std;
bool judge(int a){
if(a <= 1) return false;
int i;
for(i = 2; i < (int)sqrt(double(a)) + 1; i++){
if(a % i == 0) return false;
}
return true;
}
int main(){
int n;
while(cin >> n){
if(judge(n))
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}
若一个数不是素数,则必存在一个小于它的素数为其的因数。则在我们获得一个素数时,即将它的所有倍数均标记成非素数。按照如下步骤完成工作:从 2 开始遍历 2 到 1000000 的所有整数,若当前整数没有因为它是某个小于其的素数的倍数而被标记成非素数,则判定其为素数,并标记它所有的倍数为非素数。这种算法被我们称为素数筛法。
/***输入一个整数 n(2<=n<=10000),输出所有小于n的个位为 1 的素数,如果没有则输出-1***/
/***利用素数筛选算法和一个一维标记数组,标记出小于n的所有素数,并把全部素数放到一个数组里面,最后判断输出*******/
#include <iostream>
using namespace std;
bool isPrime[10001];
int Prime[10001];
int cnt;
void initPrime(int n){
int i, j;
for(i = 2; i <= n; i++) isPrime[i] = false;
cnt = 0;
for(i = 2; i <= n; i++){
if(!isPrime[i]){//直接从 i * i 开始标记。其原因是显然的,i * k (k < i)必已经在求得 k 的某个素因数(必小于 i)时被标记过了
for(j = i*i; j <= n; j += i)//注意此处别写成j++
isPrime[j] = true;
Prime[cnt++] = i;
}
}
return;
}
int main(){
int n;
while(cin >> n){
int i;
initPrime(n);
bool tag = false;
for(i = 0; i < cnt; i++){
if(Prime[i] % 10 == 1){
if(!tag) {cout << Prime[i]; tag = true;}
else
cout << " " << Prime[i];
}
}
if(cnt == 0) cout << -1;
cout << endl;
}
return 0;
}
七 分解素因数
对一个数 x 分解素因数即确定素数p1、p 2、... pn ,使其满足关系式:x = p1*p1*...*p2*...*pn*pn,此外,需要确定p1,p2...的幂指数。比如12=2*2*3,11=11只有1个质因数。
<span style="font-size:18px;">/***输入一个正整数 N(1<N<10^9),输出 N 的质因数的个数******/
/***先用上节的素数筛选,然后一直从最小的素数开始,一直除,至不能整除就换下一个较小的素数来整除******/
/***若遍历到最后,n 仍旧没被除成 1,则表明 n 存在一个大于 100000 的素因子,其幂指数必然为1******/
#include <iostream>
using namespace std;
#define max 40000 //设置为100000时调试出错,故设置为40000
bool isPrime[max+1];//如果最后一个素数大于40000,若其幂大于1,则超过了10^9,故幂必定为1;
short int Prime[max+1]; //如果其不为素数,则其必定为大于40000的多个素数的乘积,超过了10^9,故必定为素数。
short int PrimeSize;
void initPrime(){
int i, j;
PrimeSize = 0;
for(i = 2; i <= max; i++)
isPrime[i] = false;
for(i = 2; i <= max; i++){
if(!isPrime[i]){
for(j = i*i; j <= max; j+=i)
isPrime[j] = true;
Prime[PrimeSize++] = i;
}
}
return;
}
int main(){
int n;
initPrime();
while(cin >> n && n > 1){
int cnt = 0, i, j;
for(i = 0; i < PrimeSize; i++){
if(n % Prime[i] == 0){
while(n % Prime[i] == 0){
n /= Prime[i];
++cnt;
}
}
}
if(n != 1) ++cnt;
cout << cnt << endl;
}
return 0;
}/**也可使用两个数组ans[]和cnt[]分别保存n的素因数和对应幂,用Primecnt来保存递增的素因数个数***/</span>
n!的素因子算法:
1.计算器数组清零,存放 n!分解质因数后各个素因子 p(p为Prime[]从2开始依次对应的素数,即对应的幂指数可为0,下标和对应素数与Prime[]对应) 对应的幂指数;
2.计算 n/p,表示有 n/p 个整数可以向 n!提供一个 p 因子,则计数器累加 n/p,即1*..*p*..*2p*..*floor(n/p)*p..*n;故cnt[ap]=n/p;
3.计算 n/(p*p),有 n/(p*p)个整数可以向 n!提供两个 p 因子,即1*..*(p*p)*..*(2p*p)*..*(floor(n/(p*p))*p*p)..*n;由于k*p*p的集合必定属于k*p的集合,因此在cnt[ap]=n/p的基础上加上n/(p*p)即可;
4.计算 n/(p*p*p),有 n/(p*p*p)个整数可以向 n!提供三个 p 因子,1*..*(p*p*p)*..*(2p*p*p)*..*(floor(n/(p*p*p))*p*p*p)..*n;由于k*p*p*p的集合必定属于k*p*p的集合,因此在cnt[ap]=n/p+n/(p*p)的基础上加上n/(p*p*p)即可;
5,依次类推cnt[ap] = n/p + n/(p*p) + n/(p*p*p)+...,退出条件为n/(p^h)=0。对Prime[]中的素数都做此处理。
<span style="font-size:18px;">/***给定 n,a 求最大的 k,使 n!可以被 a^k 整除但不能被 a^(k+1)整除(2<=n<=1000),(2<=a<=1000)**********/
/***筛选素数后,先对n!进行素数分解,再对a进行素数分解,分别计算对应的幂数商值,选择最小的为输出答案**********/
#include <iostream>
using namespace std;
int cnt1[1001], cnt2[1001];
bool isPrime[1001];
int Prime[1001];
int PrimeSize;
void judgePrime(){
int i, j;
for(i = 2; i <= 1000; i++) isPrime[i] = false;
PrimeSize = 0;
for(i = 2; i <= 1000; i++){
if(!isPrime[i]){
for(j = i*i; j <= 1000; j+=i)
isPrime[j] = true;
Prime[PrimeSize++] = i;
}
}
}
int main(){
int n, a;
judgePrime();
while(cin >> n >> a){
memset(cnt1, 0, sizeof(cnt1));
memset(cnt2, 0, sizeof(cnt2));
int i, j;
for(i = 0; i < PrimeSize; i++){
//if(n % Prime[i] == 0){ //注意此处不应该加此限定条件
int t = n;
while(t){
cnt1[i] += t / Prime[i];
t /= Prime[i];
}
//}
}
for(i = 0; i < PrimeSize; i++){
if(a % Prime[i] == 0){
while(a % Prime[i] == 0){
cnt2[i]++;
a /= Prime[i];
}
}
}
int ans = 999999999;
for(i = 0; i < PrimeSize; i++){
if(cnt2[i] == 0) continue; //此处应加判断
else if(cnt1[i] == 0 && cnt2[i] != 0) {ans = 0; break;}
else if(ans > cnt1[i]/cnt2[i]) ans = cnt1[i]/cnt2[i];
}
cout << ans << endl;
}
return 0;
}</span>
八 二分求幂
以 2的 31 次方为例,我们首先求得 31 的二进制数 11111,在二进制表达式中 31 即被表达成(11111) = 2^0 + 2^1 + 2^2 + 2^3 + 2^4,这就是我们所需的分解结果。即拆
2 的 31 次为 2 的 0 次、1 次、2 次、3 次、4 次的乘积,即得到前文中所讲的结果。即2^31=2^1*2^2*2^4*2^8*2^16。
<span style="font-size:18px;">/***求 A^B 的最后三位数表示的整数*******/
/***(XXXabc*YYYdef)%1000 = ((XXX000+abc)*YYYdef)%1000 = ... = (abc*def)%1000,只需对每次的乘数和乘积去余即可******/
/***注意到 A^B 的后三位数只与 A 的后三位数和 B 有关,再使用二分求幂效率更好************/
#include <iostream>
using namespace std;
int ans[12];
int main(){
int a, b;
while(cin >> a >> b){ //对0^a,a^0做判断,运行正常
if(a == 0 && b == 0) break;
int size = 0, i;
while(b) {ans[size++] = b % 2; b /= 2;}
int result = 1;
for(i = 0; i < size; i++){
a = a % 1000;
result = result % 1000;
if(ans[i]) result = (a * result);
a = a * a;
}
cout << result%1000 << endl;
}
return 0;
}</span>
9,高精度整数
有一些整数可能数值非常巨大以至于我们不能使用任何内置整数类型来保存它的值。我们使用
struct bigInteger{
int digit[1000];
int size; //digit有内容的单元数量
};
用每个int装一个位数效果较好。
1,大整数加法(两正整数或两负整数相加)
原书采用了每个int单位保存4个位数,实际上a,b若不超过1000位,完全可以一个int单位保存1个位数,考虑到1000!的阶乘位数为3600多位,故我在处理大精度整数问题上,统一使用以一个int单位保存一位,
并在结构体中设置int digit[4001]的数组。此时耗费的内存还是远小于1MB。考虑到两负整数相加,因此需要设置一个tag表示正负并在输出时做处理。
以下为两个整数相加:
<span style="font-size:18px;">/***输入a,b,(a,b同号,小于1000位),输出a+b***/
/***设置数组str1[1001],str2[1001],结构体中digit[4001],符号标志tag,长度size,以及自定义函数**/
/***函数用途:两个正整数相加或两个负整数相加,如47883+3434,-543435+(-23433)****/
#include <iostream>
using namespace std;
char str1[1001], str2[1001];
struct BigInteger{
int digit[4001];
int size;
bool tag;
void init(){
size = 0;
memset(digit, 0, sizeof(digit));
tag = true;//true表正数
}
void set(char r[]){//存数从最低位(位于r[0]开始)开始存起,先对r[0]进行符号判断
init();
int len = strlen(r), i, start = 0;
if(r[0] == '-') {tag = false; start = 1;}
else if(r[0] == '+') {tag = true; start = 1;}
for( i = len-1; i >= start; i--) digit[size++] = r[i] - '0';
}
BigInteger operator+(const BigInteger &a) const{
BigInteger tmp;
tmp.init();
int weight = 0, i;
for(i = 0; i < size || i < a.size; i++){
tmp.digit[i] = digit[i] + a.digit[i] + weight;
weight = tmp.digit[i] / 10;
tmp.digit[i] %= 10;
}
if(weight) tmp.digit[i++] = weight;
tmp.size = i;
if(!tag) tmp.tag = false;
return tmp;
}
void output(){//输出从最高位开始输出
if(!tag) cout << "-";
int i;
for(i = size-1; i >= 0; i--) cout << digit[i];
cout << endl;
}
};
BigInteger a, b, c;
int main(){
while(cin >> str1 >> str2){
a.set(str1);
b.set(str2);
c = a + b;
c.output();
}
return 0;
}</span>
2,大整数减法(两正整数相减)
此时需要考虑到符号问题,在重载减法运算符时,做判断,先是a-b,若处理到最后的权为负值,则表明a<b,之后再用b-a并在最后输出时加个负号即可。在结构体中设置一个tag初值为true表正,在输出时根据tag做处理。
<span style="font-size:18px;">/***输入两个整数,相减,输出结果,结果可正可负****/
/***在重载减法运算符时,做判断,先是a-b,若处理到最后的权为负值,则表明a<b,之后再用b-a并在最后输出时加个负号即可****/</span>
<span style="font-size:18px;">/***函数用法:如4347437-3443或77887-3432424****/
#include <iostream>
using namespace std;
char str1[1001], str2[1001];
struct BigInteger{
int digit[4001];
int size;
bool tag;
void init(){
memset(digit, 0 ,sizeof(digit));
tag = true;
size = 0;
}
void set(char r[]){
init();
int len = strlen(r), start = 0, i;
if(r[0] == '-') {tag = false; start = 1;}
else if(r[0] == '+') start = 1;
for(i = len-1; i >= start; i--) digit[size++] = r[i] - '0';
}
BigInteger operator-(const BigInteger &a) const{
BigInteger tmp;
tmp.init();
int weight = 0, i;
for(i = 0; i < size || i < a.size; i++){
if(digit[i]- weight >= a.digit[i]){
tmp.digit[i] = digit[i] - weight - a.digit[i];
weight = 0;
}
else{
tmp.digit[i] = digit[i] - weight + 10 - a.digit[i];
weight = 1;
}
}
if(weight){
weight = 0;
tmp.tag = false;
for(i = 0; i < size || i < a.size; i++){
if(a.digit[i]- weight >= digit[i]){
tmp.digit[i] = a.digit[i] - weight - digit[i];
weight = 0;
}
else{
tmp.digit[i] = a.digit[i] - weight + 10 - digit[i];
weight = 1;
}
}
}
int j;
for(j = i-1; j >= 1; j--){ //举例,如果结果为00145,则消去0变为145
if(tmp.digit[j]) break;
}
tmp.size = j+1;
return tmp;
}
void output(){
if(!tag) cout << "-";
int i;
for(i = size-1; i >= 0; i--)
cout << digit[i];
cout << endl;
}
};
BigInteger a, b, c;
int main(){
while(cin >> str1 >> str2){
a.set(str1);
b.set(str2);
c = a - b;
c.output();
}
return 0;
}</span>
3,大整数阶乘(不超过1000位)(只能是正整数)
在结构体中设置int digit[4001]的数组。然后重载乘法运算符。
<span style="font-size:18px;">/***大整数阶乘(不超过1000位)(只能是正整数)***/
/***在结构体中设置int digit[4001]的数组。然后重载乘法运算符***/
#include <iostream>
#include <iomanip>
using namespace std;
struct BigInteger{
int digit[4001];
int size;
//bool tag;
void init(){
memset(digit, 0, sizeof(digit));
size = 0;
//tag = true;
}
void set(int n){ //set只在初始的时候用一次,且用于数值较小(int范围内)的情况
init();
do{
digit[size++] = n % 1000000;
n /= 1000000;
}while(n);
}
BigInteger operator*(const int x) const{
BigInteger tmp;
tmp.init();
int weight = 0, i;
for(i = 0; i < size; i++){
tmp.digit[i] = digit[i] * x + weight;//由于最大需要计算的是1000,根据int的最大值可知每个int单位以10000000为基准
weight = tmp.digit[i] / 1000000;//当基准太小时,如10或1000,有可能在进位的时候出错,出现负值
tmp.digit[i] %= 1000000;//后期可根据两大整数相乘对此算法进行改进
}
if(weight) tmp.digit[i++] = weight;
tmp.size = i;
return tmp;
}
void output(){
int i;
for(i = size-1; i >= 0; i--){
if(i == size-1)
cout << digit[i];
else
cout << setw(4) << setfill('0') << digit[i];
}
cout << endl;
}
};
BigInteger a;
int main(){
int num;//输入的数小于1000
while(cin >> num){
a.set(1);
int i;
for(i = num; i >= 1; i--){
a = a * i;
}
a.output();
}
return 0;
}</span>
4,两个大整数相乘(两整数相乘(可正可负))
先对正负号做判断,在结构体中设置一个tag初值为true表正,在输出时根据tag做处理。若a,b中的tag有一个为false,则乘积c的tag也为false。
<span style="font-size:18px;">/***两个大整数相乘(两整数相乘(可正可负))***/
/***先对正负号做判断,在结构体中设置一个tag初值为true表正,在输出时根据tag做处理。若a,b中的tag有一个为false,则乘积c的tag也为false***/
/***函数用法:如104589*123,-3434*34334****/
#include <iostream>
using namespace std;
struct BigInteger{
int digit[4001];
int size;
bool tag;
void init(){
size = 0;
memset(digit, 0, sizeof(digit));
tag = true;
}
void set(char r[]){
init();
int start = 0, i, len = strlen(r);
if(r[0] == '-'){start = 1; tag = false;}
else if(r[0] == '+') start = 1;
for(i = len-1; i >= start; i--)
digit[size++] = r[i] - '0';
}
BigInteger operator*(const int n) const{ //n只是一个一位数,用于大整数与另一个数的每一位相乘
BigInteger tmp;
tmp.init();
int i, weight = 0; //由于是两个一位数相乘,9*9+9=90,即不可能出现进位错误的情况
for(i = 0; i < size; i++){
tmp.digit[i] = digit[i] * n + weight;
weight = tmp.digit[i] / 10;
tmp.digit[i] %= 10;
}
if(weight) tmp.digit[i++] = weight;
tmp.size = i;
return tmp;
}
/*void move(int x){ //由于最低位存放的是个位数,需要将数组全体右移
int i;
for(i = size-1; i >= 0; i--)
digit[x+i] = digit[x]; //在这里出过错误,调了很长时间
for(i = 0; i < x; i++)
digit[i] = 0;
size = size + x;
}*/
void move(int n){ //由于从0到size默认是由低位到高位,故需在前面添加0,为大整数相乘做准备
int i;
for(i = size-1; i >= 0; i--){
digit[i+n] = digit[i];
}
for(i = 0; i < n; i++) digit[i] = 0;
size = size + n;
}
BigInteger operator+(const BigInteger &a) const{
BigInteger tmp;
tmp.init();//必须初始化
int weight = 0, i;
for(i = 0; i < size || i < a.size; i++){
tmp.digit[i] = digit[i] + a.digit[i] + weight;
weight = tmp.digit[i] / 10;
tmp.digit[i] = tmp.digit[i] % 10;
}
if(weight != 0) tmp.digit[i++] = weight;
tmp.size = i;
return tmp;
}
BigInteger operator*(const BigInteger &a) const{
BigInteger tmp, temp;
tmp.init();
temp.init();
int i, n;
for(i = 0; i < a.size; i++){
n = a.digit[i];
temp = (*this) * n;
//temp.output();
temp.move(i);
//temp.output(); //在此处进行调试
tmp = tmp + temp;
}
if(tag && a.tag) tmp.tag = true;
else if(!tag && !a.tag) tmp.tag = true;
else tmp.tag = false;
tmp.size = temp.size;
if(tmp.digit[temp.size+1]) tmp.size = temp.size + 1;
return tmp;
}
void output(){
if(!tag) cout << "-";
int i;
for(i = size-1; i >= 0; i--) cout << digit[i]; //无止境的输出一般表示++,--搞反了
cout << endl;
}
};
BigInteger a, b, c;
char str1[1001], str2[1001];
int main(){
while(cin >> str1 >> str2){
a.set(str1);
b.set(str2);
c = a * b;
c.output();
}
return 0;
}</span>
总结:两负或正整数相加或相减,最后都会演变成两正整数相加,两负整数相加或两正整数相减这三种情况。
<span style="font-size:18px;">/***将m进制的数x转换为n进制的数输出,即先后输入m,n,x。其中2<=m,n<=36,x可能是大整数.假设都以小写字母输入输出*******/
/***先用str存放m进制数x,根据重载的+和*将x转化为10机制数放到BigInteger中,在此以100000为int单位基准;*****/
/***重载取余和除法运算符,将转化的10进制数转化为n进制数,放入ans数组中*****/
#include <iostream>
#include <iomanip>
using namespace std;
#define baseline 10000
struct BigInteger{
int digit[4001];
int size;
void init(){
memset(digit, 0, sizeof(digit));
size = 0;
}
void set(int a){
init();
do{
digit[size++] = a % baseline;
a /= baseline;
}while(a);
}
void output(){
int i;
for(i = size-1; i >= 0; i--){
if(i == size-1) cout << digit[i];
else
cout << setw(4) << setfill('0') << digit[i];
}
cout << endl;
}
BigInteger operator*(const int x) const{ //高精度整数与普通整数的乘积
BigInteger tmp;
tmp.init();
int weight = 0, i;
for(i = 0; i < size; i++){
tmp.digit[i] = x * digit[i] + weight;
weight = tmp.digit[i] / baseline;
tmp.digit[i] %= baseline;
}
if (weight != 0) tmp.digit[i++] = weight;
tmp.size = i;
return tmp;
}
BigInteger operator+(const BigInteger &a) const{ //高精度整数之间的加法运算
BigInteger tmp;
tmp.init();
int weight = 0, i;
for(i = 0; i < size || i < a.size; i++){
tmp.digit[i] = a.digit[i] + digit[i] + weight;
weight = tmp.digit[i] / baseline;
tmp.digit[i] %= 10000;
}
if (weight != 0) tmp.digit[i++] = weight;
tmp.size = i;
return tmp;
}
int operator%(const int x) const{//算法:如34 05 78%8,先34对8取余得2,之后205对8取余得5,之后578对8取余得2.
int remainder = 0, i;
for(i = size-1; i >= 0; i--)
remainder = (remainder*baseline+digit[i]) % x;
return remainder;
}
BigInteger operator/(const int x) const{//算法:如34 05 78%8,先34对8取余得2,之后205对8取余得5,之后578对8取余得2.
int merchant, remainder = 0, i;
BigInteger tmp;
tmp.init();
for(i = size-1; i >= 0; i--){
tmp.digit[i] = (remainder*baseline+digit[i]) / x;//此处注意对x(进制数)取商取余
remainder = (remainder*baseline+digit[i]) % x;
}
tmp.size = 0;
for(i = 0; i < 4001; i++) {
if (digit[i] != 0) tmp.size = i;
} //若存在非0位,确定最高的非0位,作为最高有效位
tmp.size++; //最高有效位的下一位即为下一个我们不曾使用的digit数组单元,确定为size的值
return tmp;
}
}a, b;
char str[1001];
char ans[1001];
int main(){
int m, n;
while(cin >> m >> n >> str){
//a.set(14545540);
//a.output();
a.set(0);//保存十进制值
b.set(1);//保存权值
int i, x;
for(i = strlen(str)-1; i >= 0; i--){
if(str[i] <= 'z' && str[i] >= 'a')
x = 10 + str[i] - 'a';
else
x = str[i] - '0';
a = a + b*x;
b = b*m;
}
//a.output();
int cnt = 0; //代表转换为n进制的字符个数
do {
x = a % n; //求余数
//cout << x << endl;
if(x >= 10) ans[cnt++] = x - 10 + 'a';
else ans[cnt++] = x + '0'; //确定当前位字符
a = a / n; //求商
}while(a.digit[0] != 0 || a.size != 1); //当a不为0时重复该过程,之所以a.size!=1而不是0是因为,在已经set的结构体中
for(i = cnt-1;i >= 0; i--) cout << ans[i]; //size至少为1
cout << endl;
}
return 0;
}</span>