题目大意
给出
n
n
n个长度为
m
m
m的字符串,其中
n
n
n是奇数,
现在进行一波操作,
将这
n
n
n个字符串两两配对,其中有一个字符串无法配对,不妨记作
s
0
s_0
s0,
每一对字符串可以交换任意个对应位置的字母。
例如,字符串abcde
与zyxwv
,它们交换第一位,第三位之后就变为了zbxde
,aycwv
。
现在再给出 n − 1 n-1 n−1个长度为 m m m的字符串,是经过一波操作之后的字符串(但并不给出具体操作),求 s 0 s_0 s0是 n n n个长度为 m m m的字符串中的哪一个。
时间限制
1s
数据范围
n
≤
1
0
5
n \le 10^5
n≤105
m
≤
1
0
5
m \le 10^5
m≤105
n
×
m
≤
1
0
5
n \times m \le 10^5
n×m≤105
题解
判断字符串是否相等,最常用的一个办法就是hash,
不难发现,一对字符串,无论它们如何交换对应位置的字母,其的哈希值的和都是不变的。
因此,经过操作后的
n
−
1
n-1
n−1个串哈希值的和,应该等于原来
n
n
n个串中,对应的那
n
−
1
n-1
n−1个串哈希值的和。
如果知道了
n
n
n个串的哈希值的和,那么
s
0
s_0
s0的哈希值也就十分显然了。
对应哈希冲突的问题,
如果担心被hack,可以多选几个模数,变成双哈希,多哈希即可。
Code
//#pragma GCC optimize (2)
//#pragma G++ optimize (2)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <vector>
#include <queue>
#define G getchar
#define ll long long
using namespace std;
int read()
{
char ch;
for(ch = G();(ch < '0' || ch > '9') && ch != '-';ch = G());
int n = 0 , w;
if (ch == '-')
{
w = -1;
ch = G();
} else w = 1;
for(;'0' <= ch && ch <= '9';ch = G())n = (n<<1)+(n<<3)+ch-48;
return n * w;
}
const int N = 100005;
const int mo = 998244353;
struct node
{
string s;
ll hh;
bool operator < (const node & n)const
{
return hh < n.hh;
}
}a[N] , tmp;
int k[12] = {27 , 33 , 66 , 88 , 114 , 127 , 188 , 12341 , 999 , 14323 , 75754 , 39391};
int n , m;
bool bz;
ll sum , t , S;
char ch;
int main()
{
//freopen("b.in","r",stdin);
//freopen("b.out","w",stdout);
for (int T = read() ; T ; T--)
{
n = read();
m = read();
for (int i = 1 ; i <= n ; i++)
cin>>a[i].s;
//scanf("%s" , a[i].s);
for (int i = 0 ; i < 12; i++)
{
for (int j = 1 ; j <= n ; j++)
{
a[j].hh = 0;
for (int tt = 0 ; tt < m ; tt ++)
a[j].hh =(a[j].hh * k[i] + a[j].s[tt] - 'a') % mo;
}
sort(a + 1 , a + 1 + n);
bz = 1;
for (int j = 1 ; j < n ; j++)
if (a[j].hh == a[j + 1].hh)
{
bz = 0;
continue;
}
if (bz || i == 11)
{
sum = 0;
ch = G();
for (int j = 1 ; j < n ; j++)
{
t = 0;
for (; ch < 'a' || ch > 'z';ch = G());
for (int tt = 0 ; tt < m ; tt ++)
{
t = (t * k[i] + ch - 'a') % mo;
ch = G();
}
sum = (sum + t) % mo;
}
S = 0;
for (int j = 1 ; j <= n ; j++)
S = (S + a[j].hh) % mo;
tmp.hh = (S - sum + mo) % mo;
//printf("%s\n", a[lower_bound(a + 1 , a + 1 + n , tmp) - a - 1].s);
cout<<a[lower_bound(a + 1 , a + 1 + n , tmp) - a].s<<endl;
break;
}
}
}
fflush(stdout);
return 0;
}