解析

看到這道題時,有沒有想到搜尋?然後就是一通碼......然後過了。

但是,真的要用搜索嗎?

我們可以觀察一下。對於n進制中的數ii,如果ii加上某一個數jj會變成兩位數,那麼可以得到如下不等式:

i+j>n−1⇒j>n−1−ii+j>n−1⇒j>n−1−i

而滿足要求的jj的個數有n−1−(n−1−i)=in−1−(n−1−i)=i個。由此我們可以得到結論,一個字母的值就是這個字母對應的行中兩位數的個數。我們所需要做的只是驗證是否正確。那麼怎樣驗證呢?最直接的辦法是直接往裡面代,但能否用另外的方法將每個字母的值算出呢?

這個比較難想。對於一個數ii,如果想要j+kj+k的個位數為ii,必須滿足i<k<ni<k<n。那麼,假設滿足條件的kk有a[i]a[i]個,ii的值就是n−1−a[i]n−1−a[i]。a[i]a[i]只用求一個字母在兩位數的個位上出現的次數即可。

另外,如果一個數在同一行中出現了兩次,顯然也是不對的,直接結束即可。

在下面的程式碼中,因為行數是nn,所以其實是n−1n−1進位制的加法。

#include<bits/stdc++.h>

#define fu(i,q,w) for(register int i=q;i<=w;i++)
#define fd(i,q,w) for(register int i=q;i>=w;i--)
using namespace std;
typedef long long ll;
inline int read(){
int ret=0,f=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')f=-1;
while(c>='0'&&c<='9')ret=ret*10+(c-'0'),c=getchar();
return ret*f;
}
char word[10];//記錄字母
char check[10];//檢查重複
string numx,numy;//儲存輸入資料、檢查重複
map<char,int> two;//一行中兩位數個數
map<char,int> tone;//存字母在兩位數個位出現幾次
int n;
void in(){
n=read();
cin>>numx;//"+"特判輸入
fu(i,1,n-1){cin>>numx,word[i]=numx[0];}// 第一行存表頭的每個字母
fu(i,1,n-1)//從第二行開始
fu(j,1,n){cin>>numx;

if(j!=1&&j!=2)//表頭不算
if(numx==numy){printf("ERROR!");exit(0);}//發現重複輸入一定不對
numy=numx; //前後比,不要全行比
if(numx.size()==2){//統計兩位數個數
two[word[i]]++;tone[numx[1]]++;
}
}
}
void solve(){
fu(i,1,n-1)
if(two[word[i]]!=n-2-tone[word[i]]){printf("ERROR!");exit(0);}
//比較兩種演算法的結果是否相同
fu(i,1,n-1)
cout<<word[i]<<'='<<two[word[i]]<<' ';
printf("\n");
printf("%d",n-1);
}
int main(){
in();
solve();
return 0;
}