【NOIP1998 提高】 進位制位
題目
題目背景
著名科學家盧斯為了檢查學生對進位制的理解,他給出瞭如下的一張加法表,表中的字母代表數字。
題目描述
例如:
+ L K V E
L L K V E
K K V E KL
V V E KL KK
E E KL KK KV
其含義為:
\(L+L=L\),\(L+K=K\),\(L+V=V\),\(L+E=E\)
\(K+L=K\),\(K+K=V\),\(K+V=E\),\(K+E=KL\)
⋯
\(E+E=KV\)
根據這些規則可推匯出:\(L=0\)
同時可以確定該表表示的是 \(4\) 進位制加法。
輸入格式
第一行一個整數 \(n(3 \le n \le 9)\)
以下 \(n\) 行,每行包括 \(n\) 個字串,每個字串間用空格隔開。
若記 \(s_{i,j}\)表示第 \(i\) 行第 \(j\) 個字串,資料保證 \(s_{1,1}=+\) , \(s_{i,1}=s_{1,i}\) , \(|s_{i,1}=1|\) , \(s_{i,1} \neq s_{j,1} (i \neq j)\)
保證至多有一組解。
輸出格式
第一行輸出各個字母表示什麼數,格式如:\(L=0\) \(K=1 ……\)
按給出的字母順序排序。不同字母必須代表不同數字。
第二行輸出加法運算是幾進位制的。
若不可能組成加法表,則應輸出\(ERROR!\)。
輸入輸出樣例
輸入 #1
5
+ L K V E
L L K V E
K K V E KL
V V E KL KK
E E KL KK KV
輸出 #1
L=0 K=1 V=2 E=3
4
思路
進位制數?
一個顯然的想法是,字母所代表的數字不重複,所以進位制數\(l\)一定大於等於字母個數\(n-1\),即\(l \geq n-1\)
那麼到底是幾進位制?可以考慮列舉,注意資料範圍\((3 \leq n \leq 9)\),如果可以列舉進位制數\(l\)
每個字母所代表的?
我們先嚐試構建個特殊的加法表,設\(a_{i,j}\)所代表的數字為\(digit_{i,j}\),構造一個字母表\((digit_{i_1,1} \leq digit_{i_2,1}\),且\(i_1 \leq i_2\),\(l=10\)),看看能否找找其中的規律?
+ 0 1 2 3 4 5 6
0 0 1 2 3 4 5 6
1 1 2 3 4 5 6 7
2 2 3 4 5 6 7 8
3 3 4 5 6 7 8 9
4 4 5 6 7 8 9 10
5 5 6 7 8 9 10 11
6 6 7 8 9 10 11 12
觀察每個斜線上的數字,可以發現,在\(2 \leq i,j \leq n\)時,每個數字出現的次數\(cnt\)減去\(1\)就是當前數字。
我們得到了一個特殊的情況,那麼該種情況能否向外推?
試著去手玩一下,任意交換兩個數字,保證加法表成立,只需要將對應的行與列都交換。
例如將以下加法表 第一個 第二個數字交換
+ 0 1 2 3
0 0 1 2 3
1 1 2 3 4
2 2 3 4 5
3 3 4 5 6
| |
V V
+ 1 0 2 3
1 2 1 3 4
0 1 0 2 3
2 3 2 4 5
3 4 3 5 6
顯然成立
因為只是交換了數字的位置,是整行整列的交換,而沒有直接改變數字,所以每個數字出現的次數\(cnt\)不變。
(原諒我想不出更加嚴謹的證明,只能“顯然”一下了)
那麼擴充套件到字母,同理,可以得出每個字母代表的數字為其出現的次數\(cnt-1\)
實現
對於處理每個字母出現的次數,可以採用\(map\),可以轉為\(ASCII\)碼開陣列,這裡我採用\(map\)
先記錄次數,再按\(l\)列舉,判斷合法性即可
CODE
#include <bits/stdc++.h>
using namespace std;
string a[10][10];
map<char,int>cnt;
int main(){
int n;
int ans=0;
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) cin>>a[i][j];
for(int i=2;i<=n;i++)
for(int j=2;j<=n;j++){
if(a[i][j].size()==1)
cnt[a[i][j][0]]++;
}
for(int l=n-1;l<=10;l++){
bool f=1;//標記 方案是否合法
for(int i=2;i<=n;i++){
for(int j=2;j<=n;j++){
int sum=0;
for(int k=a[i][j].size()-1;k>=0;k--){
sum+=(cnt[a[i][j][k]]-1)*pow(l,a[i][j].size()-k-1);//l進位制下的數字轉換為10進位制 方便比較
}
if(sum!=(cnt[a[i][1][0]]-1+cnt[a[1][j][0]]-1)){f=0; break;}//方案非法 可以列舉下一個進位制了
}
if(!f) break;
}
if(!f) continue;
ans=l;
break;
}
if(ans==0){
puts("ERROR!");
}else{
for(int i=2;i<=n;i++) cout<<a[1][i][0]<<'='<<cnt[a[1][i][0]]-1<<' ';
puts("");
cout<<ans<<endl;
}
}