原题:
E. Swapping Characters
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
We had a string s consisting of n lowercase Latin letters. We made k copies of this string, thus obtaining k identical strings s1, s2, …, sk. After that, in each of these strings we swapped exactly two characters (the characters we swapped could be identical, but they had different indices in the string).
You are given k strings s1, s2, …, sk, and you have to restore any string s so that it is possible to obtain these strings by performing aforementioned operations. Note that the total length of the strings you are given doesn’t exceed 5000 (that is, k·n ≤ 5000).
Input
The first line contains two integers k and n (1 ≤ k ≤ 2500, 2 ≤ n ≤ 5000, k · n ≤ 5000) — the number of strings we obtained, and the length of each of these strings.
Next k lines contain the strings s1, s2, …, sk, each consisting of exactly n lowercase Latin letters.
Output
Print any suitable string s, or -1 if such string doesn’t exist.
Examples
input
3 4
abac
caab
acba
output
acab
input
3 4
kbbu
kbub
ubkb
output
kbub
input
5 4
abcd
dcba
acbd
dbca
zzzz
output
-1
Note
In the first example s1 is obtained by swapping the second and the fourth character in acab, s2 is obtained by swapping the first and the second character, and to get s3, we swap the third and the fourth character.
In the second example s1 is obtained by swapping the third and the fourth character in kbub, s2 — by swapping the second and the fourth, and s3 — by swapping the first and the third.
In the third example it’s impossible to obtain given strings by aforementioned operations.
中文:
给你k个字符串,长度都是n,现在让你找到一个字符串,使得上面的k个字符串交换其中的两个字符以后能够变成你找到的那个字符串。
#include<bits/stdc++.h>
using namespace std;
int n,k;
string s[2501];
int mark[2501];
int abc[27],tmp[27];
int flag;
int main()
{
ios::sync_with_stdio(false);
while(cin>>k>>n)
{
for(int i=1;i<=k;i++)
cin>>s[i];
if(k==1)
{
swap(s[1][0],s[1][1]);
cout<<s[1]<<endl;
continue;
}
memset(mark,0,sizeof(mark));
memset(abc,0,sizeof(abc));
flag=0;
for(int i=2;i<=k;i++)
{
for(int j=0;j<n;j++)
if(s[1][j]!=s[i][j])
mark[i]++;
}
for(int i=0;i<n;i++)
abc[s[1][i]-'a']++;
int m=0;
for(int i=0;i<26;i++)
if(abc[i]>1)
m=1;
for(int i=2;i<=k;i++)
{
memset(tmp,0,sizeof(tmp));
for(int j=0;j<n;j++)
tmp[s[i][j]-'a']++;
for(int j=0;j<26;j++)
{
if(abc[j]!=tmp[j])
{
flag=1;
break;
}
}
if(flag)
break;
}
if(flag)
{
cout<<-1<<endl;
continue;
}
int res,flag2=0;
for(int i=0;i<n;i++)
{
for(int j=i+1;j<n;j++)
{
flag=0;
for(int x=1;x<=k;x++)
{
res=mark[x];
if(s[1][i]!=s[x][i])
res--;
if(s[1][j]!=s[x][j])
res--;
if(s[1][i]!=s[x][j])
res++;
if(s[1][j]!=s[x][i])
res++;
if((res==0&&m)||res==2)
flag++;
else
break;
}
if(flag==k)
{
flag2=1;
swap(s[1][i],s[1][j]);
cout<<s[1]<<endl;
break;
}
}
if(flag2)
break;
}
if(!flag2)
cout<<-1<<endl;
}
return 0;
}
解答:
首先判断这k个字符串能不能找到一个最终的目标字符串s,如果能找到,那肯定是每个字符串里面,每个字符对应的个数都相同。
判断完以后,以给定的第一个字符串s1为样本,枚举字符串s1的两个位置,然后比对剩下k-1个字符串是否能通过交换他们当中的两个字符就能够获得和s1一模一样的字符串。如下:
for(int i=0;i<s1.size();i++)//s1的下标
{
for(int j=i+1;j<s1.size();j++)//s1的下标
{
//交换s1[i]和s1[j]是否能够满足剩下k-1字符串的变换需求
for(int x=1;x<=k;x++)
。。。。。
}
}
在枚举s1交换了第i和j两个字母以后,如何判断余下的k-1个是否能够符合交换两个字符以后能够变成s1。
受到时间复杂度的限制,需要考虑一下其他的办法。
首先对剩下的k-1个字符串进行预处理,记录在mark当中,记录每个字符与s1不同字符的个数。
因为,再s1交换了两个位置的字符以后,剩下的k-1个字符串如果可以通过交换两个位置的字符从而变成交换后的s1,那么只有2个位置的字符不同,或者没有不同。
所以,每次枚举了s1的交换位置i和j以后,判断剩下的k-1个字符串的mark值是否差了2或者0即可。
由于mark当中记录的是每个k-1个字符串于没有交换第i和第j个字符串的不同值,所以在枚举s1的位置并交换以后,要重新算一下。
最后注意可能有的字符串每个字符只有一个,那么能交换的成功的条件就只有剩下的字符交换后与s1一模一样。