洛谷P1013(进制位)

题目描述

著名科学家卢斯为了检查学生对进位制的理解,他给出了如下的一张加法表,表中的字母代表数字。 例如:

+    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;
}
洛谷P1168题目是关于中数线段树解法的问题。中数线段树解法可以通过维护两个堆来实现。一个是大根堆,一个是小根堆。每次插入元素时,根据一定的规则来维护这两个堆,使得大根堆的个数在一定情况下比小根堆多1或者相等。大根堆的最后一个元素即为中数。具体的规则如下: 1. 如果大根堆和小根堆的个数相等,下一次插入的元素一定插入到大根堆。此时判断小根堆的堆顶是否大于当前元素x,如果是,则将小根堆的堆顶元素插入到大根堆,然后将x压入小根堆;否则直接将x压入大根堆。 2. 如果大根堆和小根堆的个数不相等,按照类似的规则进行操作。 通过以上规则,可以实现在每次插入元素时,维护两个堆的平衡,并且保证大根堆的最后一个元素即为中数。 这种解法的时间复杂度为O(logN),其中N为序列的长度。 #### 引用[.reference_title] - *1* *2* [中数(洛谷p1168)(堆/树状数组+二分/线段树+二分)](https://blog.csdn.net/qq_45604735/article/details/114382762)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [洛谷 P1168 中数(权值线段树,离散化)](https://blog.csdn.net/qq_38232157/article/details/127594230)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值