🔗 UVA-10093 An Easy Problem!

tags: 數學(Math)

範例程式碼已於 UVA瘋狂程設(CPE)ZeroJudge 上皆測試通過。

題意

給定一個 NN 進位制的整數 RR,你需要找出 NN 的最小可能值,使得 RR 可以被 (N1)(N-1) 整除,如果不存在這樣的 NN,則輸出 "such number is impossible!"

NN 的範圍是 226262,其中 6262 進位制使用 0099AAZZaazz 作為數字符號,6161 進位制使用 0099AAZZ 以及 aayy 作為數字符號,依此類推。

比較古老的翻譯中提到,測資可能是包含非合法字元的,所以要先判斷是不是英文或數字。

LuckyCat 的中文翻譯

思路:數學(Math)

首先以 1010 進位為例,在國中小中時我們學過如何判定 99 的倍數,也就是一個數字 R=a0+a110+a2102++an10nR = a_0 + a_1 \cdot 10 + a_2 \cdot 10^2 + \cdots + a_n \cdot 10^n 是否可以被 99 整除,可以用 ai\sum a_i 是否可以被 99 整除來判定。這個方法可以推廣到其他進位制。

也就是說,一個數字 R=a0+a1N+a2N2++anNnR = a_0 + a_1 \cdot N + a_2 \cdot N^2 + \cdots + a_n \cdot N^n 可以被 (N1)(N-1) 整除,等同 ai\sum a_i 可以被 (N1)(N-1) 的倍數整除,具體證明如下:

  1. 首先,對於 NkN^k ,其除以 (N1)(N-1) 的餘數為 11 ,由以下推導可知:
    • Nk=(N1)Nk1+Nk1N^k = (N-1) N^{k-1} + N^{k-1},因此 NkN^k 除以 (N1)(N-1) 的餘數為等同 Nk1N^{k-1} 除以 (N1)(N-1) 的餘數,可以遞迴到 N0N^0 除以 (N1)(N-1) 的餘數為 11 為止。
  2. 故可以得出 akNka_k \cdot N^k 除以 (N1)(N-1) 的餘數為 aka_k
  3. 因此 R=a0+a1N+a2N2++anNnR = a_0 + a_1 \cdot N + a_2 \cdot N^2 + \cdots + a_n \cdot N^n 除以 (N1)(N-1) 的餘數為 a0+a1+a2++an=aia_0 + a_1 + a_2 + \cdots + a_n = \sum a_i
  4. 若餘數 ai\sum a_i 可以被 (N1)(N-1) 整除,則 RR 可以被 (N1)(N-1) 整除。

得出上述結論後,可以先預處理 s=ais = \sum a_i,再從 N=max(ai)+1N = \max(a_i) + 1 開始遞增地嘗試找到符合條件的最小 NN 即可。

複雜度分析

  • 時間複雜度:O(n)\mathcal{O}(n) ,其中 nn 為輸入字串的長度,或是也可以視為數字 RR 的位數。
  • 空間複雜度:O(n)\mathcal{O}(n)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
while True:
try:
line = input().strip()
except EOFError:
break
A = [] # 逐位轉換成數字
for ch in line:
if ch.isdigit(): # [0, 9]
A.append(int(ch))
elif ch.isupper(): # [10, 35]
A.append(ord(ch) - ord("A") + 10)
elif ch.islower(): # [36, 61]
A.append(ord(ch) - ord("a") + 36)

ans = -1
r = max(A) + 1 # 最小必須為 base-r
s = sum(A)
for i in range(max(2, r), 63):
if s % (i-1) == 0:
ans = i
break
print(ans if ans != -1 else "such number is impossible!")
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
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'

int main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int ans, s, mx;
string line;
while (cin >> line) {
vector<int> A;
for (char ch : line) {
if (isdigit(ch)) A.push_back(ch - '0');
else if (isupper(ch)) A.push_back(ch - 'A' + 10);
else if (islower(ch)) A.push_back(ch - 'a' + 36);
}
s = 0;
mx = -1;
for (int x : A){
mx = max(mx, x);
s += x;
}
ans = -1;
for (int i = max(2, mx + 1) ; i <= 62; ++i) {
if (s % (i - 1) == 0) {
ans = i;
break;
}
}
cout << (ans == -1 ? "such number is impossible!" : to_string(ans)) << endl;
}
return 0;
}

寫在最後

Cover photo is remixed from @Tiffany, thanks for his/her work!