P1017

[NOIP2000 提高组] 进制转换

比较好想的一个做法是转换表示。

因为奇数次幂的 $-R$ 是个负数,而偶数次幂的 $-R$ 是正的,在表示正数 $n$ 的时候,我们可以采取如下策略:

首先用 $R$ 进制表示该数。

假如说第 $k$ 位是奇数位,这一位的数字为 $a_k$,我们可以用 $a_{k+1}\times (-R)^{k+1}+(R-a_k)\times (-R)^k$ 来表示。

于是乎先这样表示,再在后面处理进位即可。

可以分 $n$ 的正负来讨论。

负数与正数同理,不过是把奇数位和偶数位的作用颠倒一下。

时间复杂度在 $O(\log n)$ 级别。

当然也可以直接转化负进制数,以上的过程可以用类似于短除法的方法搞出来。

带余除法搞出该位余数之后,C++ 下的除法中如果把这一位的数字搞成负数了,就说明该位应该用上述方法表示出来,那么我们把余数换正,再把剩下的商加 1,相当于向下一位借一个 1。

其实分奇偶位的实质是在向下一位借一个 1。

代码(分奇偶位讨论):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;

const ll N=1e3;

ll R,tmp,m,n;

ll a[N+5];

char s[22]={'0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H','I','J','K','L'};

inline ll read() {
ll ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-f;ch=getchar();}
while(ch>='0'&&ch<='9') {ret=(ret<<3)+(ret<<1)+ch-'0';ch=getchar();}
return ret*f;
}

void write(ll x) {
static char buf[22];static ll len=-1;
if(x>=0) {
do{buf[++len]=x%10+48;x/=10;}while(x);
}
else {
putchar('-');
do{buf[++len]=-(x%10)+48;x/=10;}while(x);
}
while(len>=0) putchar(buf[len--]);
}

int main() {

n=read();R=read();tmp=n;

write(n);putchar('=');

if(n==0) {
write(n);
printf("(base%lld)",R);
}
if(n>0) {
R=-R;m=-1;
while(tmp) {
a[++m]=tmp%R;tmp/=R;
}
for(ll i=0;i<=m;i++) {
if(a[i]!=0&&(i&1)) {
a[i]=R-a[i];a[i+1]++;
}
a[i+1]+=a[i]/R;a[i]%=R;
}
while(a[m+1]>0) {
m++;
if(m&1) {
a[m]=R-a[m];a[m+1]++;
}
a[m+1]+=a[m]/R;a[m]%=R;
}
for(ll i=m;i>=0;i--) putchar(s[a[i]]);
R=-R;
printf("(base%lld)",R);
}
if(n<0) {
R=-R;m=-1;tmp=-tmp;
while(tmp) {
a[++m]=tmp%R;tmp/=R;
}
for(ll i=0;i<=m;i++) {
if(a[i]!=0&&!(i&1)) {
a[i]=R-a[i];a[i+1]++;
}
a[i+1]+=a[i]/R;a[i]%=R;
}
while(a[m+1]>0) {
m++;
if(!(m&1)) {
a[m]=R-a[m];a[m+1]++;
}
a[m+1]+=a[m]/R;a[m]%=R;
}
for(ll i=m;i>=0;i--) putchar(s[a[i]]);
R=-R;
printf("(base%lld)",R);
}

return 0;
}

代码(带余除法):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;

const ll N=1e3;

ll R,m,n;

ll a[N+5];

char s[22]={'0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H','I','J','K','L'};

inline ll read() {
ll ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-f;ch=getchar();}
while(ch>='0'&&ch<='9') {ret=(ret<<3)+(ret<<1)+ch-'0';ch=getchar();}
return ret*f;
}

void write(ll x) {
static char buf[22];static ll len=-1;
if(x>=0) {
do{buf[++len]=x%10+48;x/=10;}while(x);
}
else {
putchar('-');
do{buf[++len]=-(x%10)+48;x/=10;}while(x);
}
while(len>=0) putchar(buf[len--]);
}

int main() {

n=read();R=read();
write(n);putchar('=');

m=-1;
while(n) {
a[++m]=n%R;n/=R;
if(a[m]<0) {a[m]-=R;n++;}
}

for(ll i=m;i>=0;i--) {
putchar(s[a[i]]);
}

printf("(base%lld)",R);

return 0;
}