1010 Radix (25 分)

一、问题描述

在这里插入图片描述
输入两个数N1、N2,和一个标记tag、一个基数radix,其意义是:tag为1时,radix是N1的基数;tag为2时,radix是N2的基数。方便起见,以下假定tag为1,则目标就是找到一个尽可能小的基数,使N2在此基数下的值等于N1在radix下的值。例如二进制下的110等于十进制下的6。

二、思路

做过的都知道,思路是不难的,就是坑实在不少,要想的全面一点。
1、暴力算法:基数从2一直取到N1,当基数能使N2=N1时停止:有测试用例运行超时,扑街。
2、二分法:
基数的最小值:N2的最大权值+1(数=权值+基数),例如N2中最大的权值是a(也就是10),那么这个数至少是11进制的。
基数的最大值:
N1+1。为什么是N1+1呢?当N2只有一位时,其大小与基数无关,例如:只要基数大于8,那么8这个数不管是在16进制下还是20进制下,都是8(10进制下),因为任何基数的0次方都是1嘛;当N2有两位或以上时,倒数第二位最小是1,那么基数为N1+1时,这个数就必然会大于等于N1+1,所以再大就没有必要比较了。
那么能不能是N1呢?反正在我这个程序里是不行的,因为代码里当最小值(start)大于最大值(end)时,会返回0(Impossible),那么当N1=10,N2=a时,start=a+1=11,end=10,所以输出Impossible,但显然在11进制下10=a,出现这种情况的原因就是:大于等于a的数虽然是以一位呈现出来,但是真实值在10进制下是两位。(为了统一,可以把10进制下的两位数10,看作是11进制下的一个符号‘10’,哈哈哈哈哈)
常见的坑:
基数可能会很大,导致N2按此基数算出来之后超过longlong的表示范围,不过我们只需要加一条判断,当N2溢出变成负数时(显然使N1=N2成立的基数如果存在的话一定会小于当前基数),我们去小的那一半里去找基数;
基数最小为2;
基数不能小于等于N2里最大的权值;
等等……

三、代码

#include <iostream>
using  namespace std;
long long int getNum(string str,long long int radix){
//作用:按照基数radix,将字符串转化str为数
//可能会很大,用longlong
    long long int sum=0;
    for (size_t i = 0; i < str.length(); ++i) {
        if (str[i] <= '9')sum = sum * radix + (str[i] - '0');
        //注意‘0’-'9’,和a-z不连续
        else if(str[i]<='z')sum=sum*radix+(str[i]-'a'+10);
    }
    return sum;
}
long long int getRadix(long long int num1,string str,long long int start,long long int end){
//主要滴代码
    if(start==end){
    //等号单独讨论,否则可能死循环
        if(getNum(str,start)==num1)return start;
        else return 0;
    }
    else if(start<end){
        long long int radix=(start+end)/2;
        //二分查找
        if(getNum(str,radix)==num1)return radix;
        //num2>num1或num2<0都表示这个radix取得过大了,需要减小
        else if(getNum(str,radix)>num1||getNum(str,radix)<0)return getRadix(num1,str,start,radix);
        //num2<num1,说明radix取得比较小,所以要往大了取
        else return getRadix(num1,str,radix+1,end);
    }
    return 0;
}
int getMinRadix(string num2){
//作用:找到num2的最小基数
//例如:num2中最大的权值为b时,最小基数就是b+1=12
    char max='0';
    for (int i = 0; i < num2.length(); ++i)
        if(num2[i]>max)max=num2[i];
    if (max <= '9')return max-'0'+1;
    else return max-'a'+11;
}
int main()
{
    string str1,str2;
    int tag;
    long long int radix;
    cin>>str1>>str2>>tag>>radix;
    long long int num1;
    //根据tag=1或2,作相应调整## 
    if(tag==1){
        num1=getNum(str1,radix);
    }
    else{
        num1=getNum(str2,radix);
        str2=str1;
    }
    //几种特殊情况
    if(num1==0&&str2=="0"){//试了一下,测试用例没有这种情况
        cout<<"2";
        return 0;
    }
    auto res=getRadix(num1,str2,getMinRadix(str2),num1+1);
    if(res==0){
        cout<<"Impossible";return 0;
    }
    cout<<res;
    return 0;
}

明明刚吃完午饭,抬头一看,又到了吃晚饭的点了

w(゜Д゜)w

二刷:

#include<iostream>
using namespace std;
long long int getNum(string s, long long int radix) {
 long long int sum = 0;
 for (int i = 0; i < s.size(); i++) {
  int val = s[i] >= 0 && s[i] <= '9' ? s[i] - '0' : s[i] - 'a' + 10;
  sum = sum * radix + val;
 }
 return sum;
}
int main() {
 string s1, s2;
 int tag, maxR = 0;
 long long int radix;
 cin >> s1 >> s2 >> tag >> radix;
 long long int a = tag == 1 ? getNum(s1, radix) : getNum(s2, radix);
 s2 = tag == 1 ? s2 : s1;
 for (int i = 0; i < s2.size(); i++) {
  if (s2[i] <= '9' && s2[i] >= '0')maxR = maxR > s2[i] - '0' ? maxR : s2[i] - '0';
  else if (s2[i] >= 'a' && s2[i] <= 'z')maxR = maxR > s2[i] - 'a' + 10 ? maxR : s2[i] - 'a' + 10;
 }
 long long int start = maxR + 1, end = a + 1;
 while (start <= end) {
  long long int ans = (start + end) / 2;
  long long int temp = getNum(s2, ans);
  if (start == end && temp != a) {
   break;
  }
  else if (temp == a) {
   cout << ans << endl;
   return 0;
  }
  else if (temp > a || temp < 0)end = ans;
  else
   start = ans + 1;
 }
 cout << "Impossible" << endl;
 return 0;
}
  • 13
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值