[NOIP1998 提高组] 进制位
[NOIP1998 提高组] 进制位
题意:
给定一个字母表 \(S\),第一行或第一列代表了所有的字符,每个字符对应一个数,且 \(s[i][1]=s[1][i]\)。
其中 \(S[i][j]\) 表示 \(S[1][i]+S[j][1]\) 。
请你求出每个字母对应的数字和进位制,如果不行输出 \(ERROR!\)
分析:
首先可以有两个结论:
1. 如果有 \(n\) 个字符,那么进位一定是 \(n\) 。
证明:
因为有 \(n\) 个不同的数,所以肯定是 \(n\) 进制往上。
如果进制为 \(n+1\) 进制,那么一定有一个数没有出现,假设为 \(k\) 。
- \(k=0\) 或 \(k=1\),而 \(1+n=10\) ,矛盾。
- \(1 \geq k \geq n\) ,而 \(1+(k−1)=k\) ,矛盾。
因此得证
2. 如果 \(i\) 这一列/行有 \(cnt\) 个两位的字符,那么这个 \(s[i][1]\) 字符代代表的数的就是 \(cnt\) 。
证明:
因为这个数和其他所有数都进行了加的计算,感性理解一下就可以证明。
因此,我们就可以愉快的做题了。
用 \(map\) 保存每个字符对应的值,然后再扫一遍判断以下是否合法就行了。
字符处理有点恶心,我是把长度为 \(2\) 的字符拆成了两个字符,分开算。
代码:
// P1013 [NOIP1998 提高组] 进制位
#include<bits/stdc++.h>
using namespace std;
int n;
char s[12][12][5];
int len[12][12];
int cnt[12];
map<char,int> mp;
int main(){
cin>>n; int m=n-1;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
char a[3]; scanf("%s",a); if(i==1&&j==1) continue;
len[i][j]=strlen(a);
if(len[i][j]==1) s[i][j][0]=a[0];
else cnt[j]++,s[i][j][0]=a[0],s[i][j][1]=a[1];
}
}
for(int i=2;i<=n;i++) mp[s[1][i][0]]=cnt[i];
int flag=0;
for(int i=2;i<=n;i++)
for(int j=2;j<=n;j++){
if(len[i][j]==1){
int a=mp[s[1][i][0]],b=mp[s[1][j][0]],c=mp[s[i][j][0]];
if(a+b!=c) flag=1;
}
else{
int a=mp[s[1][i][0]],b=mp[s[1][j][0]],c=mp[s[i][j][0]],d=mp[s[i][j][1]];
if(a+b!=c*m+d) flag=1;
}
}
//虽然好多特判都没判,但是数据实在太水了就过了
if(flag==1) puts("ERROR!");
else{
for(int i=2;i<=n;i++) cout<<s[1][i][0]<<"="<<cnt[i]<<" ";
puts(""); cout<<m<<endl;
}
system("pause");
return 0;
}
不关注的有难了😠😠😠https://b23.tv/hoXKV9