PAT A1010-基数(二分法)
カジュアルワーキング
正の整数の組を考えると、例えば、図6および110は、この式(6)= 110が真であることができますか?答えはyes
6は、小数点数であり、110は二進数であれば、。
今、正の整数のいずれかのペアのN 1およびN 2は、あなたのタスクは、他のものを与えている間に1数の基数を見つけることです。
入力仕様:
各入力ファイルには、1つのテストケースが含まれています。各ケースは4つの正の整数を含む行を占めています。
N1 N2 tag radix
ここでN1
とN2
、それぞれには10個の以上の数字を持っていません。数字は、以下の基数よりもセット{0-9、から選択されるa
- z
} 0-9進数0-9を表し、a
- z
小数点数10-35を表します。最後の数字は、radix
の基数であるN1
場合はtag
1であり、またはN2
場合tag
2です。
出力仕様:
式はそのように、各テストケースのために、一列に他の数の基数を印刷N1
= N2
真です。式が不可能な場合は、印刷しますImpossible
。解決策が一意でない場合は、出力可能な最小基数。
サンプル入力1:
6 110 1 10
サンプル出力1:
2
サンプル入力2:
1 ab 1 2
出力例2:
Impossible
図4は、実質的に、最初の数の数であるN1
、第二の数N2
、第3の数は、tag
正面を示しN1
、N2
最後の数が前記radix
示す塩基であるtag
基数数が指定された数です。
これらのデータにより、我々は作り、最小限の基盤を見つける必要があるN1
= N2
設立します。
上記の例では、N1 = 6
、、 、、N2 = 110
本明細書に記載されるように、すなわち進番号10の塩基数であり、それは計算により発見されたバイナリ数の、同じ値。2が出力されます。tag = 1
radix = 10
N1
N2
N1
N2
問題解決のためのアイデア
この質問は、比較を含むが、ここではN1
とN2
私たちN1、N2は比較するための十進数に変換されているので、別の16進数を含むことができます。N1
簡単進数に変換するために、N2
我々はベースの複数横断する必要がありradix
、計算に対応する塩基、N2
小数の値、その後N1
比較し、それらが等しい場合、それは我々が探していることであってもよいですradix
。
その後、のためにradix
複数のパスを取得する必要がありますので、ここで私たちは二分法を使用しています。これは、第1の境界値を決定する必要があり、下限はleft
カジュアルな作業に応じて、決定することは容易である「A digit is less than its radix and is chosen from the set
」情報がちょうど見つける必要がある与えられN2
た最大値をdigit
--max、その後は順番ににすることができleft = max + 1
、ボーダーのためにright
、2つの方法があります:1、left
2によって疲れ、非常に多くのことを数サイクル後に知ることができます。塩基数として計算前N2
より少ない小数点値よりもN1
、塩基として計算し、この数と現在のN2
小数点値よりも大きい場合はN2
、それが上限であると知ることができる、などの現在選択された数が見出さright
缶。2、直接方法があるN1
として計算上限プラス小数点値right
。この理論的根拠はあるのright
上限ベース、決定基数-1
ごとでdigit
、上限を設定がある場合はこれだけ、重要なを取るright
少なく、この値よりも、そのときN2
の時間が唯一のもので、Aの値はいえすでにに等しいN1
小数の計算が、上限によって制限され、正解に到着しません。場合N2
の数、ゼロでない値で、最後の1で、この値が存在し、それを行うことができるright
服用でradix
、小数点の結果を時間よりも大きくなければならないN1
ので、権利があるかどうかことを保証することのradix
私達の設定した間隔で、それが含まれている必要があります内部。
データは10個のテストポイントは、複数の提出が通過し、最終的に変更することができない非常に大規模な操作ですので、基本的な考え方と、それから、非常に重要な点は、大きな選択する変数の整数、そこにあるlong long
にunsigned long long
。
コード
#include <stdio.h>
#include <string.h>
using namespace std;
// 把字符串转化为十进制数
unsigned long long int stod(char snum){
if(snum <= '9' && snum >= '0') return snum - '0';
return snum - 'a' + 10;
}
// 计算数字N的十进制数值
unsigned long long int compute(int len, char *N, unsigned long long int radix){
unsigned long long int sum = 0;
for(int i = 0; i < len; i++){
sum = sum * radix + stod(N[i]);
}
return sum;
}
int main() {
char N[2][11];
int tag, len[2];
unsigned long long int right, left = 0, mid, radix, sum, osum = 0, theother;
// 读取数据
scanf("%s %s %d %lld",N[0], N[1], &tag, &radix);
len[0] = (int)strlen(N[0]);
len[1] = (int)strlen(N[1]);
//N1-0;N2-1于是当tag=1->N1,另一个就是theother = 2-1 =1->N2
theother = 2-tag;
tag = tag - 1;
sum = compute(len[tag], N[tag], radix);// 计算tag指定的目标字符串代表的数的十进制值
for(int i = 0; i < len[theother]; i++){// 找到另一个字符串的最大值
if(left < stod(N[theother][i])) left = stod(N[theother][i]);
}
// 边界值确定
left += 1;
right = sum + 1;
while (left <= right){
mid = (left + right) / 2;
osum = compute(len[theother], N[theother], mid);
if(osum > sum){
right = mid - 1;
}
else if(osum < sum){
left = mid + 1;
}
else if(osum == sum){
printf("%lld", mid);
return 0;
}
}
printf("Impossible\n");
return 0;
}