题目描述
著名科学家卢斯为了检查学生对进位制的理解,他给出了如下的一张加法表,表中的字母代表数字。 例如:
+ 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,K=1,V=2,E=3
同时可以确定该表表示的是4进制加法
输入格式
n (n≤9)表示行数。
以下n行,每行包括n个字符串,每个字串间用空格隔开。(字串仅有一个为‘+’号,其它都由大写字母组成)
输出格式
1.各个字母表示什么数,格式如:L=0,K=1,……按给出的字母顺序。
2.加法运算是几进制的。
3. 若不可能组成加法表,则应输出“ERROR!”
题目解法
洛谷里大神好多啊,这一次我会整理一下各种思路,最后再亮出代码。
0级解法
不知道有没有人和我一样,一开始看到这题的时候,想用解方程的方法做,先在(n-1)*(n-1)个数中挑选n个数出来解方程,之后把结果代入表格中看是否能对上,但是这样复杂度蛮高的,而且acm不支持matlab,用c++去解方程想想就头疼,而且解方程中,遇到有进位的数,又不知道进制,这就很麻烦了。
1级解法
在这个表中,必定存在有进位的数,且进制必为n-1,所要求的数必定是0,1,2,3,…,n-2这些数且只出现一次,为什么呢?请听我娓娓道来。
首先是为什么一定有进位呢?假设所有字符中对应的值最大是X,那么表中必有一项是X+X的,但是这样的话就没办法用其它字符表示,只可能是有进位存在。
然后,如果有进位,那么这些数中一定存在1,1+1=2,就一定有2,1+2=3,就一定有3,…1+n-3=n-2,同时因为进位,字符里必定有表示0的字符。注意到,这里0,1,2,3,…n-2一共n-1个数了,刚好对应了n-1个字符,这也说明了进制至少是n-1,同时,注意到,1+(n-2)=n-1,这是一个不存在于上面那串数字中的数,只可能是用有进位的数表示的,所以进制至多是n-1。然后就说明了进制是n-1。(有点像高数求极限里夹逼定理)
2级解法
这是一位大佬提出的解法,我真想把膝盖献给他(她),这是对1级解法的完美升华啊!
注意表中单字符的数据,x=0+x=1+(x-1)=2+(x-2)=…=(x-2)+2=(x-1)+1=x+0,注意到,如果一个字符在表中单字符中出现了x次,那么它就是x-1,简单粗暴。
3级解法
希望我能遇到,或者有人知道的话一定要不吝赐教。
Talking is cheap,show you my code.
代码
#include<iostream>
#include<string>
#include<map>
using namespace std;
string s[9][9];
int num[9];
map<string, int> mymap;
int main() {
int n;
cin >> n;
for (int i = 0;i < n;i++) {
for (int j = 0;j < n;j++) {
cin >> s[i][j];
}
}
for (int i = 1;i < n;i++) {
mymap.insert(pair<string,int>(s[0][i],-1));
}
for (int i = 1;i < n;i++) {
for (int j = 1;j < n;j++) {
if (s[i][j].size() == 1) {
mymap[s[i][j]] += 1;
}
}
}
for (int i = 1;i < n;i++) {
for (int j = 1;j < n;j++) {
int t = 0;
for (int ii = 0;ii < s[i][j].size();ii++) {
t *= (n - 1);
t += mymap[s[i][j].substr(ii, 1)];
}
int tt = mymap[s[i][0]] + mymap[s[0][j]];
if (t != tt) {
cout << "ERROR!" << endl;
return 0;
}
}
}
for (int i = 1;i < n;i++) {
cout << s[0][i] << "=" << mymap[s[0][i]] << " ";
}
cout << endl;
cout << (n - 1) << endl;
return 0;
}