​传送门​

P1013 [NOIP1998 提高组] 进制位_#define

题意:

给你一个由字母代表数字的加法表,问你这个加法是几进制以及每个字母所代表的数字是多少。

思路:

动手稍微模拟一下就会发现:
1.表中一定会有进位。当表中有数字x时,那就一定会有数字x2,x4…一直到出现进位。
2.由于第一列和第一行的字符串长度都为1,那么可以的到这个表一定是n-1进制的。还是基于第一点,结合加法表和进位的特点,可以得到:最终一定会出现0到n-1的所有数。
所以只需要先找到0,再找到1,就可以推出后面的字母了。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
#define pb push_back
#define p push
const int mod = 998244353;
string s[20][20];
char vis[200];
int pos[200];
int ans[20][20];
int num[200];

int main()
{
int n;
cin>>n;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
cin>>s[i][j];
}
}
int flag = 0;
for(int j = 2; j <= n; j++)
{
if(s[j][j] == s[1][j])
{
vis[0] = s[j][j][0];
pos[s[j][1][0]] = j;
num[s[j][1][0]] = 0;
}
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
if(s[i][j].size() == 2)
{
if(s[i][j][1] == vis[0])
{
vis[1] = s[i][j][0];
num[s[i][j][0]] = 1;
flag = 1;
}
}
}
}
for(int i = 2; i <= n; i++)
if(s[1][i][0] == vis[1])pos[vis[1]] = i;
if(!flag)
{
cout<<"ERROR!";
return 0;
}
for(int i = 2; i < n-1; i++)
{
int f = 0;
for(int j = 2; j <= n; j++)
{
if(num[s[1][j][0]] + 1== i)
{
f = 1;
pos[s[pos[vis[1]]][j][0]] = j;
num[s[pos[vis[1]]][j][0]] = i;
vis[i] = s[pos[vis[1]]][j][0];
}
}
if(!f)
{
cout<<"ERROR!";
return 0;
}
}
flag = 0;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
if(i==1 || j==1)continue;
ans[i][j] = num[s[1][j][0]]+num[s[i][1][0]];
int sum = 0;
for(int k = 0; k < s[i][j].size(); k++)
{
sum = sum*(n-1)+num[s[i][j][k]];
}
if(sum!=ans[i][j])
{
cout<<"ERROR!";
return 0;
}
}
}
for(int i = 2; i <= n; i++)
{
cout<<s[1][i]<<"="<<num[s[1][i][0]]<<" ";
}
cout<<endl<<n-1<<endl;
}