对于两个字符串,如果他们逐位相等,那么便称这两个字符串相等,但是大多数情况下,字符串是不相等的,所以小度定义如果将几种字符修改成字符 * 之后,两个字符串逐位相等了,那么便称这两个字符串好像相等。
现在给定一个长度为 nn 的仅包含小写字母的字符串 ss,多次询问对于该字符串的 [l1,r1][l1,r1] 子串与 [l2,r2][l2,r2] 子串,是否相等,如果不相等,那么将他们变成好像相等,至少需要将多少种字符修改成字符 *,并输出字符种类。
输入格式:
第 1 行读入 2 个数字 n,qn,q,分别代表字符串长度,以及询问的次数;
第 2 行读入一个字符串 ss,保证该字符均为小写字母;
随后 qq 行每行读入 4 个正整数 l1,r1,l2,r2l1,r1,l2,r2;
数据范围保证 1≤n,q≤1051≤n,q≤105, 1≤l1,l2,r1,r2≤n1≤l1,l2,r1,r2≤n,l1≤r1l1≤r1,l2≤r2l2≤r2,r1−l1=r2−l2r1−l1=r2−l2。**
输出格式:
对于每次询问,输出两行:
第一行输出至少需要将多少种字符修改成 *,如果两个字符串完全相等,则输出 0;
第二行从小到大输出需要修改的字符种类,中间不间隔。**
样例 1
输入:
9 3
abccbedbe
5 6 8 9
1 3 4 6
1 3 7 9
输出:
0
3
ace
4
acde
样例解释:
对于字符 be 等于字符 be,所以输出 0
对于字符 abc 好像相等字符 cbe,需要将 a ,c ,e 修改成 * 才能好像相等。
对于字符 abc 等于字符 dbe,需要将 a,d ,c,e 修改成 * 才能好像相等。
赛后补了一下这题,发现正解是用的26个字符串哈希,分别记录(a-z)的哈希值
比如"abcda"中的a,"a a"字符串哈希为a131^4+0131^3+0131^2+0131^1+a*131^0,然后(a-z)每个字母比较一下,不一样就输出它,复杂度为O(n+q)*O(26)。
但是考试想不到,首先n,q都是10^5,所以肯定不能暴力走一遍,如果能记录(a-z)在原字符串的位置,然后在要查询的两个字符串中用二分找一下在原文中出现的字符的位置,然后分别比较第一个,最后一个出现的位置是不是一样,再比较一下长度,再预处理前缀和,比较一下是不是完全一样即可,这个返回发虽然麻烦,但也能过,注意要取消同步流,要不会超时O(n+q)*O(26)*O(logn),最后卡在915ms惊险ac。
附上代码:
#include <bits/stdc++.h>
using namespace std;
unsigned long long int h[(int)(1e5+5)];
unsigned long long int p[(int)(1e5+5)];
unsigned long long int string_hash(int l,int r)
{
return h[r]-h[l-1]*p[r-l+1];
}
vector <int> qian[30];
vector < vector<long long int> > qian_he( 30 , vector<long long int>(1e5+5,0) );
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
for(int i=0;i<30;i++) qian[i].clear();
int n,q;cin>>n>>q;
string s;cin>>s;
s="#"+s;
for(int i=1;i<=n;i++)
{
qian[(int)(s[i]-'a')].emplace_back(i);
}
for(int i=0;i<26;i++)
{
//cout<<i<<": ";
for(int j=1;j<=qian[i].size();j++)
{
qian_he[i][j]=qian_he[i][j-1]+qian[i][j-1];
//cout<<qian_he[i][j]<<" ";
}
//cout<<'\n';
}
h[0]=0;
p[0]=1;
for(int i=1;i<=n;i++)
{
p[i]=p[i-1]*131;
h[i]=h[i-1]*131+(unsigned long long int)(s[i]);
}
while(q--)
{
int l1,r1,l2,r2;cin>>l1>>r1>>l2>>r2;
///cout<< string_hash(l1,r1) <<" "<<string_hash(l2,r2)<<'\n';
if( string_hash(l1,r1) == string_hash(l2,r2) )
{
cout<<0<<'\n'<<'\n';
}
else
{
vector <char> ans;
for(int i=0;i<26;i++)
{
int index_start_1=lower_bound(qian[i].begin(),qian[i].end(),l1)-qian[i].begin();
int index_over_1=upper_bound(qian[i].begin(),qian[i].end(),r1)-qian[i].begin()-1;
int zuo1,you1,len1;
if( index_start_1>index_over_1 ) zuo1=-1,you1=-1,len1=-1;
else zuo1=qian[i][index_start_1],you1=qian[i][index_over_1],len1=index_over_1-index_start_1+1;
int index_start_2=lower_bound(qian[i].begin(),qian[i].end(),l2)-qian[i].begin();
int index_over_2=upper_bound(qian[i].begin(),qian[i].end(),r2)-qian[i].begin()-1;
int zuo2,you2,len2;
if( index_start_2>index_over_2 ) zuo2=-1,you2=-1,len2=-1;
else zuo2=qian[i][index_start_2],you2=qian[i][index_over_2],len2=index_over_2-index_start_2+1;
//cout<<"index_start_1="<<index_start_1<<" index_over_1="<<index_over_1<<" index_start_2="<<index_start_2<<" index_over_2="<<index_over_2<<'\n';
//cout<<"len1="<<len1<<" len2="<<len2<<'\n';
//cout<<"zuo1="<<zuo1<<" yuo1="<<you1<<" zuo2="<<zuo2<<" you2="<<you2<<'\n';
if(zuo1==-1&&you1==-1&&zuo2==-1&&you2==-1&&len1==-1&&len2==-1) continue;
long long int cha1=qian_he[i][index_over_1+1]-qian_he[i][index_start_1];
long long int cha2=qian_he[i][index_over_2+1]-qian_he[i][index_start_2];
//cout<<"cha1="<<cha1<<" cha2="<<cha2<<'\n';
if( zuo1-l1==zuo2-l2 && len1==len2 && abs(cha1-cha2)==abs(zuo1-zuo2)*len1 ) continue;
ans.emplace_back( (char)('a'+i) );
}
cout<<ans.size()<<'\n';
for(auto it:ans) cout<<it;
cout<<'\n';
}
}
return 0;
}