1010 Radix 需再做
Posted CSU迦叶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了1010 Radix 需再做相关的知识,希望对你有一定的参考价值。
目录
总结
1. 短小精悍的一道二分算法题,总体思路是,将字符串1(如果tag不是1将两个字符串调换一下即可)转化为10进制,再用二分法看能否找到另一个进制使得两个字符串的10进制数相等。
2. 本题的三个函数关系是binarySearch调用cmp,cmp调用getDec,其中getDec是用来吧已知进制的数转化成十进制,但是转化成十进制中有可能会超过LL的范围(字符串一保证不会,虽然题中没说),也就是溢出,会得到负数,如果溢出了说明必然是n2>n1,可以把这种情况和n2>n1并列返回一个特殊的数1。那么cmp接收到1也就知道n2>n1。
3. 这道题还给我的一个启发是,二分法虽然要求单调函数的背景,但是这个单调函数未必要一步到位,可以通过嵌套来降低难度,只是要做好单元测试。
一些细节:
1.这道题已经出现了很多long long,不妨将有可能超过int的数据类型全部改成LL,防止运算过程错误。
2.对于二分查找的下界,应该是字符串2当中达到的最高位数加一,上界应该是max(下界,字符串1对应的10进制数)。这个比较难想到。
3.把字符转化成数字的数组LL Map[128],(1)用字符做下标巧妙利用了系统强制类型转换,(2)另写用来初始化这个数组的函数init()容易忘记调用,(3)对于a-z的赋值,记得加10。
解题过程
第一次的想法是,二分法里面的单调函数放把确定进制的字符串转化为十进制数的函数。也就是下面的getDec(),然后我设想的二分区间是[2,100],得到如下代码。得分为22/25。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 10;
const int INF = 1000000000;//INF:下确界
const int SUP = (1LL<<63)-1;//SUP:上确界
const double eps = 1e-5;
LL getDec(char A[],int radix){//随着radix的值增大, 得到的res值也会增大
int len = strlen(A);
LL res = 0;
for(int i=0;i<len;i++){
int temp;
if(A[i]>='0'&&A[i]<='9')temp = A[i]-'0';
if(A[i]>='a'&&A[i]<='z')temp = A[i]-'a'+10;
res = res*radix + temp;
}
return res;
}
int binarySearch(char B[],LL x){
int l=2,r=200,mid;
while(l<=r){
mid = l+(r-l)/2;
if(getDec(B,mid)==x)return mid;
if(getDec(B,mid)>x){
r = mid - 1;
}else{
l = mid + 1;
}
}
return -1;
}
int main(){
char n1[20],n2[20];
int tag,radix;
scanf("%s %s %d %d",n1,n2,&tag,&radix);
if(tag == 2){//默认tag等于1,不然就交换
char temp[20];
strcpy(temp,n1);
strcpy(n1,n2);
strcpy(n2,temp);
}
LL x = getDec(n1,radix);
int res = binarySearch(n2,x);
if(res == -1)printf("Impossible\\n");
else printf("%d\\n",res);
return 0;
}
这个想法显然有问题,首先,没有考虑到换算成十进制的过程可能产生溢出,其次,二分区间并非是[2,100]。于是查了参考书,写出如下AC代码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 10;
const int INF = 1000000000;//INF:下确界
const LL SUP = (1LL<<63)-1;//SUP:上确界
const double eps = 1e-5;
LL Map[128];
void init(){//初始化字符映射数组,方面用于进制的数字表示 0-9对应0-9 a-z对应10-35
for(char c='0';c<='9';c++){
Map[c] = c - '0';
}
for(char c='a';c<='z';c++){
Map[c] = c - 'a'+10;//加10容易漏
}
}
LL getDec(char A[],LL radix,LL ceil){//需要判断是否溢出
int len = strlen(A);
LL res = 0;
for(int i=0;i<len;i++){
res = res*radix + Map[A[i]];
if(res<0||res>ceil)return -1;//溢出或者是超过N1的十进制
}
return res;
}
int cmp(char B[],LL radix,LL ceil){
int len = strlen(B);
LL num = getDec(B,radix,ceil);
if(num==-1)return 1;//说明n2>n1
if(num<ceil)return -1;//n2<n1
else if(num == ceil)return 0;//n2==n1
else return 1;//n2>n1
}
LL binarySearch(char B[],LL l,LL r,LL x){
LL mid;
while(l<=r){
mid = l+(r-l)/2;
if(cmp(B,mid,x)==0)return mid;
if(cmp(B,mid,x)>0){
r = mid - 1;
}else{
l = mid + 1;
}
}
return -1;
}
LL getLowerbound(char B[]){
int len = strlen(B);
LL res = 0;
for(int i=0;i<len;i++){
res = max(res,Map[B[i]]);
}
return res+1;//res是最大数位,二分区间要从res+1开始
}
int main(){
char n1[20],n2[20];
int tag,radix;
scanf("%s %s %d %d",n1,n2,&tag,&radix);
if(tag == 2){//默认tag等于1,不然就交换
char temp[20];
strcpy(temp,n1);
strcpy(n1,n2);
strcpy(n2,temp);
}
init();
LL x = getDec(n1,radix,SUP);
LL l = getLowerbound(n2);
LL r = max(l,x);
LL res = binarySearch(n2,l,r,x);
if(res == -1)printf("Impossible\\n");
else printf("%lld\\n",res);
return 0;
}
以上是关于1010 Radix 需再做的主要内容,如果未能解决你的问题,请参考以下文章