1010. Radix (25)

题目链接:http://www.patest.cn/contests/pat-a-practise/1010

题目:

 
 
时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

Given a pair of positive integers, for example, 6 and 110, can this equation 6 = 110 be true? The answer is "yes", if 6 is a decimal number and 110 is a binary number.

Now for any pair of positive integers N1 and N2, your task is to find the radix of one number while that of the other is given.

Input Specification:

Each input file contains one test case. Each case occupies a line which contains 4 positive integers: N1 N2 tag radix Here N1 and N2 each has no more than 10 digits. A digit is less than its radix and is chosen from the set {0-9, a-z} where 0-9 represent the decimal numbers 0-9, and a-z represent the decimal numbers 10-35. The last number "radix" is the radix of N1 if "tag" is 1, or of N2 if "tag" is 2.

Output Specification:

For each test case, print in one line the radix of the other number so that the equation N1 = N2 is true. If the equation is impossible, print "Impossible". If the solution is not unique, output the smallest possible radix.

Sample Input 1:
6 110 1 10
Sample Output 1:
2
Sample Input 2:
1 ab 1 2
Sample Output 2:
Impossible

分析:

题目的意思是给你两个数,并且一个tag标识是哪一个数是什么进制的,问你有没有可能与另外进制的另一个数相同
比如Sample 1中的6 和 110,下面的1说明第1个数6是10进制的,它刚好和第二个数110的2进制相同,所以输出2。
这一题做了好久,刚开始一直有案例过不去。
这里还有一个非常容易忽视的点,就是当你用遍历的时候你超时了,但是当你用二分查找的时候,你答案又错误了。
这是因为针对一个比较小的数字比如3 3 1 10,当第一个数字是3时,其实照理说后面那个3是大于4的进制都可以,但是题目希望你输出的是10。
同样的,对于一个可以是多个答案的进制来说,题目希望你输出的是最小的进制(除了前面两个数字相同的情况下)

刚开始没用二分查找,而是直接从2遍历到num1 + 1的,出现了超时的情况。

#include<stdio.h>
#include<string.h>
using namespace std;
char str1[11];
char str2[11];
char str_tmp[11];
long long i, j;
long long real_num(char *str, long long r){//找出其十进制的数对应的是多少
 long long sum = 0, tmp;
 for (i = 0; str[i] != 0; i++){
  sum *= r;
  if (str[i] >= '0' && str[i] <= '9')
   tmp = str[i] - '0';
  else if (str[i] >= 'a' && str[i] <= 'z')
   tmp = str[i] - 'a' + 10;
  if (tmp >= r)return -1;
//当位数上的数字大于进制时,是不可能的
  sum += tmp;
 }
 return sum;
}
int main(void){
 long long tag, radix;
 long long num1, num2;
 while (scanf("%s %s %lld %lld", str1, str2, &tag, &radix) != EOF){
  if (strcmp(str1, str2) == 0){
   printf("%lld\n", radix);
   continue;
  }//如果两个字符串相同,说明进制相同。
  if (tag == 2){
   strcpy(str_tmp, str2);
   strcpy(str2, str1);
   strcpy(str1, str_tmp);
  }//如果tag为2,那么交换str1和str2,相当于都变为tag为1的情况。
  num1 = real_num(str1, radix);
/*  	long long base = 1, top = num1 + 1, mid;
  while (base <= top){
   mid = (base + top) / 2;
   num2 = real_num(str2, mid);
   if (num2 == num1)break;
   else if (num2 > num1)top = mid - 1;
   else base = mid + 1;
  }//这里要用二分查找,不然会有超时的情况
  if (num1 == num2)printf("%lld\n", mid);
  else {  */
   long long ans = -1;
   for (j = 2; j < num1 + 2; j++){
    long long num2 = real_num(str2, j);
    if (num2 == num1){
     ans = j;
     break;
    }
//这里现在只用了遍历
    else if (num2 > num1)break;
   }
   if (ans == -1)puts("Impossible");
   else printf("%lld\n", ans);
  }
//	}
 return 0;
}


可是当我只用二分查找的时候,而没有遍历的时候,却用出现答案错误的情况。
这就是我们上面提到的,当你碰到两个数字比如10 5 1 5,前面一个说明了是一个5进制的10也就是10进制的5,题目希望你输出的6,而不是大于6的其他数字。所以用二分查找是有问题的,因为它能最快找到答案,但不是最小的答案。

#include<stdio.h>
#include<string.h>
using namespace std;
char str1[11];
char str2[11];
char str_tmp[11];
long long i, j;
long long real_num(char *str, long long r){//找出其十进制的数对应的是多少
 long long sum = 0, tmp;
 for (i = 0; str[i] != 0; i++){
  sum *= r;
  if (str[i] >= '0' && str[i] <= '9')
   tmp = str[i] - '0';
  else if (str[i] >= 'a' && str[i] <= 'z')
   tmp = str[i] - 'a' + 10;
  if (tmp >= r)return -1;
 //当位数上的数字大于进制时,是不可能的
  sum += tmp;
 }
 return sum;
}
int main(void){
 long long tag, radix;
 long long num1, num2;
 while (scanf("%s %s %lld %lld", str1, str2, &tag, &radix) != EOF){
  if (strcmp(str1, str2) == 0){
   printf("%lld\n", radix);
   continue;
  }//如果两个字符串相同,说明进制相同。
  if (tag == 2){
   strcpy(str_tmp, str2);
   strcpy(str2, str1);
   strcpy(str1, str_tmp);
  }//如果tag为2,那么交换str1和str2,相当于都变为tag为1的情况。
  num1 = real_num(str1, radix);
   long long base = 1, top = num1 + 1, mid;
  while (base <= top){
   mid = (base + top) / 2;
   num2 = real_num(str2, mid);
   if (num2 == num1)break;
   else if (num2 > num1)top = mid - 1;
   else base = mid + 1;
  }//这里要用二分查找,不然会有超时的情况
  if (num1 == num2)printf("%lld\n", mid);
 /*	else {  
   long long ans = -1;
   for (j = 2; j < num1 + 2; j++){
    long long num2 = real_num(str2, j);
    if (num2 == num1){
     ans = j;
     break;
    }
    else if (num2 > num1)break;
   }
   if (ans == -1)
   */
  else puts("Impossible");
  //	else printf("%lld\n", ans);
  //}
 }
 return 0;
}



最后,无奈了,那就先二分查找搞定第7个案例的超时的情况,然后再遍历一遍搞定其余几个答案错误的情况。
虽然有些麻烦,感觉像是两遍遍历,似乎后面的遍历没有用,但是看过上面的分析之后你会发现是不能少的。

AC代码:
#include<stdio.h>
#include<string.h>
using namespace std;
char str1[11];
char str2[11];
char str_tmp[11];
long long i,j;
long long real_num(char *str,long long r){//找出其十进制的数对应的是多少
 long long sum = 0,tmp;
 for(i = 0; str[i] != 0; i ++){
  sum *= r;
  if(str[i] >= '0' && str[i] <= '9')
   tmp = str[i] - '0';
  else if(str[i] >= 'a' && str[i] <= 'z')
   tmp = str[i] - 'a' + 10;
  if(tmp >= r)return -1; //当位数上的数字大于进制时,是不可能的
  sum += tmp;
 }
 return sum;
}
int main(void){
 long long tag,radix;
 long long num1,num2;
 while(scanf("%s %s %lld %lld",str1,str2,&tag,&radix) != EOF){
  if(strcmp(str1,str2) == 0){
               printf("%lld\n",radix);
               continue;
            }//如果两个字符串相同,说明进制相同。
  if(tag == 2){
   strcpy(str_tmp, str2);
   strcpy(str2, str1);
   strcpy(str1, str_tmp);
  }//如果tag为2,那么交换str1和str2,相当于都变为tag为1的情况。
  num1 = real_num(str1, radix);
  long long base = 1,top = num1 + 1,mid;
  while(base <= top){
   mid = (base + top) / 2;
   num2 = real_num(str2,mid);
   if(num2 == num1)break;
   else if(num2 > num1)top = mid -1;
   else base = mid + 1;
  }//这里要用二分查找,不然会有超时的情况
  if(num1 == num2)printf("%lld\n",mid);
  else {
   long long ans = -1;
             for(j = 2; j < num1 + 2; j ++){
    long long num2 = real_num(str2,j);
                if(num2 == num1){
     ans = j;
     break;
    }//再遍历一遍。
    else if(num2 > num1)break;
                   }
             if(ans == -1)puts("Impossible");
             else printf("%lld\n",ans);
  }
 }
 return 0;
}




P.S:其实经过上面这么多分析,你会发现其实代码还可以略作优化,最后不再重新遍历一遍,而是直接从mid开始递减,到num1和num2不相等为止,这样就可以得到最小的mid了。
额,试了没成功。

——Apie陈小旭
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值