题目链接:P1017 [NOIP2000 提高组] 进制转换 - 洛谷 | 计算机科学教育新生态
题目难度:普及一
题目分析:这是道数学题,我们都知道,首先按照10进制转成n进制的做法:对这个数不断除以n,将余数一一存储,最后倒序输出,而对于此处原数和进制数都有可能为负数,也就意味着余数可能为负数,那么我们不可能输出像-100-100这种数。
我们基本思路分两点:
- 把负数转成符合n进制余数规律的正数
- 让转得的正数符合余数的计算模式
我们先来探讨一下二进制余数的规律:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
那么规律就是0101010101…… |
那么我们只需让负数余数规律也为010101……,就解决了。
我们发现,每一组数,他们对应的间隔区间内的数是相等的。那么我们只需跳到它前面一个区间的数即可,因为区间长度为-m,(m为进制)。那么就转换成:
j-=m(j为原先算出来的负数,m为进制数)
- 让转得的正数符合余数的计算模式
光转成正数还不够,因为还不符合余数的计算。
众所周知,我们令n为被除数,m为除数和进制数,a为商,j为余数,可以得到:
n/m=a
n-a*m=j
根据我们刚刚推得的算法:j-=m,那么此时方程2两端同时减去m,得
n-a*m-m=j-m
提公因式,得
n-(a+1)*m=j-m
但我们还要让j-m符合余数计算模式,即符合n-a*m=j的形式。
显然,此时a=a+1正好符合n-a*m=j的形式。所以:
n++(此时n已经/=m)
代码部分:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;int n,r;
char ch[100010];
int l;int read() {int s = 0, f = 1;char ch = getchar();while (ch < '0' || ch > '9') {if (ch == '-') f = -1;ch = getchar();}while (ch >= '0' && ch <= '9') {s = s * 10 + ch - '0';ch = getchar();}return s * f;
}int main() {n = read(),r = read();cout << n << "=";while(n != 0){int j = n % r;n /= r;if(j < 0) j -= r,n ++;if(j < 10) ch[++l] = (char)(j + 48);else ch[++l] = (char)((j - 10) +'A');}for(int i = l; i >= 1; i--) cout<<ch[i];cout<<"(base"<<r<<")"<<endl;return 0;
}