2019 百度之星初赛第二场 度度熊与排列

题目名称:度度熊与排列

题目链接:

Problem Description

度熊有一个机器,这个机器有一个1~M 的排列 p [ 1.. M ] p[1..M] p[1..M] 当作参数,若丢进一个长度为 M M M 的字符串,此机器会将此字符串重新排列后再输出,重新排列的方式为:原本第 i个位置的字符会变到第 p [ i ] p[i] p[i] 个位置。

举例来说,当 M M M=3,p[1]=3,p[2]=1,p[3]=2那么丢 “abc” 进入这个机器后,机器会输出"bca";若丢进的是 “ded”,那么机器会输出 “edd”。

某天,度熊不小心忘记这个机器的参数了,只记得参数的长度是 M M M,于是他丢了 N N N长度为 M M M 的字符串进去,并记录下对于每个字符串机器的输出结果,请你根据这些结果,帮度熊找回这个机器的参数。若有多组参数都满足度熊的记录,请输出字典序最小的排列作为参数。若并不存在任何参数满足度熊的记录,请输出 −1。

注:对于两个相异的排列a: a [ 1.. M ] a[1..M] a[1..M] b [ 1.. M ] b[1..M] b[1..M],我们称 a 比 b 小当且仅当 存在一个 i,满足对于所有小于 i 的 j 都有 a ​ j ​ ​ = b ​ j a_​j​​=b_​j aj=bj​​ 且 a i &lt; b i a_i &lt; b_i ai<bi​​。

Input

有多组询问,第一行包含一个正整数 T T T 代表有几组询问。

每组询问的第一行包含两个正整数 N , M N,M N,M,分别代表度熊丢进机器的字符串数目以及参数的长度。接下来还有 2 × N 2×N 2×N行,每行有一个长度为 M M M 的字符串,当中的第 2 × i − 1 2×i−1 2×i1 行的字符串代表度熊丢进去机器的第 i i i 个字符串,而第 2 × i 2×i 2×i 行的字符串代表机器对于第 iii 个字符串的输出结果。

1 ≤ T ≤ 100 1≤T≤100 1T100

1 ≤ N ≤ 20 1≤N≤20 1N20

1 ≤ M ≤ 50 1≤M≤50 1M50

字符串由英文小写字母(‘a’ 至 ‘z’) 组成

Output

对于每一个询问,输出一行,若不存在任何参数满足度熊的记录,这行只包含一个整数 − 1 −1 1。否则这行包含一个排列,代表此机器所有可能的参数中字典序最小的那个。

Sample Input

4
1 3
abc
bca
2 4
aaab
baaa
cdcc
cccd
3 3
aaa
aaa
bbb
bbb
ccc
ccc
1 1
a
z

Sample Output

3 1 2
2 4 3 1
1 2 3
-1

解题思路

第一眼看过去就是简单的字符串位置变换,就匆匆写完提交了,Worry Answer,然后仔细审题才发现第二组数据有多个输入,思考以后决定使用Map<int,int> mp[60]这个函数来判断,对于第 i i i次输入 mp[i]存储丢进的字符串M在对应串中每个字符可能的位置
如下:
aaab
baaa
则 第一个字符a对应的可能位置为 2,3,4
第二个字符a对应的可能位置为2,3,4
第三个字符a对应的可能位置为2,3,4
第四个字符对应的可能位置为1
接下来是第二组输入
cdcc
cccd
第一个字符c对应的可能位置为1,2,3
第二个字符d对应的可能位置为4
第三个字符c对应的可能位置为1,2,3
第四个字符对应的可能位置为1,2,3
几次输入完成后会得到如下结果
以第一个字母为例子:
位置 1 映射次数 1次
位置 2 映射次数 2次
位置 3 映射次数 2次
位置 4 映射次数 1次
检索出现次数的最大值且第一次出现的位置,于是判断 字符a出现位置为2
同理 得出编码顺序 2 4 3 1
mark数组作为标记,防止同样的字母在已经被映射的位置再次被映射,可以继续查找下一个合适的位置
使用chec函数来判断字符串是否符合题目条件,符合则执行接下来步骤,不符合直接输出-1

完整代码

#include<iostream>
#include<string>
#include<map>
#include<cstdio>
#include<cstring>
using namespace std;
int t,n,m;
string s1,s2;
int table[30],mark[60];
map<int,int> mp[60];
bool flag;
void check(){
	for(int i=0;i<m;i++){
		for(int j=0;j<m;j++){
			if(s1[i]==s2[j]){
				mp[i][j]++;
			}
		} 
	} 
}

void chec(){    // 判断是否符合提意
	if(flag==false){
		return ;
	}
	memset(table,0,sizeof(table));
	memset(mark,0,sizeof(mark));
	for(int i=0;i<m;i++){
		mark[s1[i]-'a']++;
	}	
	for(int i=0;i<m;i++){
		table[s2[i]-'a']++;
	}
	for(int i=0;i<27;i++){
		if(mark[i]!=table[i]){
			flag=false;
			return ;
		}
	}
	
}

int main()
{
//	freopen("in.txt","r",stdin);
	cin>>t;
	while(t--){
		for(int i=0;i<60;i++) mp[i].clear();
		cin>>n>>m;
		cin.ignore();
		flag=true;
		for(int i=0;i<n;i++){
			cin>>s1>>s2;
			check();
			chec();
		}
		memset(mark,0,sizeof(mark));
		int maxV,ind;
		// first 坐标 second 次数 
		if(flag){
		for(int i=0;i<m;i++){
			maxV=0;
			ind=0;
			for(map<int,int>::iterator it=mp[i].begin();it!=mp[i].end();it++){
				if(maxV<it->second&&!mark[it->first+1]){
					maxV=it->second;
					ind=it->first+1;
				}
			}
			mark[ind]=1;
			if(i!=m-1) cout<<ind<<' ';
			else cout<<ind<<endl; 
		}
		}else{
			cout<<"-1"<<endl;
		}
		
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值