[洛谷 P1013] 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,K=1,V=2,E=3,同时可以确定该表表示的是4进制加法

输入格式

n(n≤9)表示行数。

以下n行,每行包括n个字符串,每个字串间用空格隔开。(字串仅有一个为‘+’号,其它都由大写字母组成)

输出格式

① 各个字母表示什么数,格式如:L=0,K=1,……按给出的字母顺序。

② 加法运算是几进制的。

③ 若不可能组成加法表,则应输出“ERROR!”

样例输入

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

样例输出

L=0 K=1 V=2 E=3
4

解析

看到这道题时,有没有想到搜索?然后就是一通码......然后过了。

但是,真的要用搜索吗?

我们可以观察一下。对于n进制中的数\(i\),如果\(i\)加上某一个数\(j\)会变成两位数,那么可以得到如下不等式:
\[ i+j>n-1 \Rightarrow j>n-1-i \]
而满足要求的\(j\)的个数有\(n-1-(n-1-i)=i\)个。由此我们可以得到结论,一个字母的值就是这个字母对应的行中两位数的个数。我们所需要做的只是验证是否正确。那么怎样验证呢?最直接的办法是直接往里面代,但能否用另外的方法将每个字母的值算出呢?

这个比较难想。对于一个数\(i\),如果想要\(j+k\)的个位数为\(i\),必须满足\(i<k<n\)。那么,假设满足条件的\(k\)\(a[i]\)个,\(i\)的值就是\(n-1-a[i]\)\(a[i]\)只用求一个字母在两位数的个位上出现的次数即可。

另外,如果一个数在同一行中出现了两次,显然也是不对的,直接结束即可。

在下面的代码中,因为行数是\(n\),所以其实是\(n-1\)进制的加法。

代码

#include <iostream>
#include <cstdio>
#include <string>
#define N 10
using namespace std;
int n,i,j,a[N],num[30];
char l[N];
int main()
{
    cin>>n;
    for(i=0;i<n;i++){
        char c;
        cin>>c;
        if(c!='+') l[i]=c;
    }
    for(i=2;i<=n;i++){
        string s1,s;
        for(j=1;j<=n;j++){
            cin>>s;
            if(j==1) continue;
            if(j!=2&&s==s1){
                cout<<"ERROR!"<<endl;
                return 0;
            }
            s1=s;
            if(i!=1&&j!=-1){
                int l=s.length();
                if(l==2){
                    a[i-1]++;
                    num[(int)s[l-1]]++;
                }
            }
        }
    }
    for(i=1;i<n;i++){
        if(a[i]!=n-2-num[(int)l[i]]){
            cout<<"ERROR!"<<endl;
            return 0;
        }
    }
    for(i=1;i<n;i++){
        cout<<l[i]<<"="<<a[i]<<' ';
    }
    cout<<endl<<n-1<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/LSlzf/p/11129724.html