Let’s Swap(思维+hash)4星
题意:
已知一个长度为n的字符串 S S S,可以对字符串进行一种操作:
- 将字符串 S S S从下标 i ( 1 ≤ i ≤ n ) i(1\leq i\leq n) i(1≤i≤n)的位置将串分为两个串 A 、 B A、B A、B
- 将字符串 S S S变为 B A BA BA
- 反转字符串 S S S
给你两个数 a 、 b a、b a、b代表可以选取的下标的位置,允许操作任意次(或不操作)
问 S S S是否可以通过操作变成目标串 C C C
多组输入
1 ≤ T , s u m ∣ S ∣ ≤ 5 ∗ 5 10 1\leq T,sum|S|\leq 5*5^{10} 1≤T,sum∣S∣≤5∗510
题解:
由于只能选取两个位置进行操作,考虑操作的方案:(假设 a > b a>b a>b)
-
只执行一次 a a a或只执行一次 b b b——按照题目所述操作即可
-
执行多次操作
-
显然连续选取同一位置进行操作是无效的
-
考虑先选 a a a再选 b b b,用打表可知字符串操作变为:
选择位置 j = n − ( a − b ) j=n-(a-b) j=n−(a−b)将串 S S S分为串 A 、 B A、B A、B,将串变为 B A BA BA
若多次执行当前先选 a a a再选 b b b的操作,则字符串始终按照循环节为 j j j进行操作
-
考虑先选 b b b再选 a a a,同上只不过 j = a − b j=a-b j=a−b
-
考虑 a 、 b a 、 b a 、 b a 、 b a . . . a、ba、ba、ba、ba... a、ba、ba、ba、ba...的情况,只需要求出按 a a a执行一次操作的串 S 1 S1 S1,然后就变成了上面的情况
-
b 、 a b 、 a b 、 a b 、 a b . . . b、ab、ab、ab、ab... b、ab、ab、ab、ab...同理
-
如何判断三个串 S 、 S 1 、 S 2 S、S1、S2 S、S1、S2是否可以通过上述操作来变成 C C C?
由上述推断可得,只要我们枚举按照循环节 j j j操作之后的字符串,若能得到串 C C C,说明yes,否则是no
匹配字符串可以用hash来判断,因为要判断循环节,所以可以将字符串都变成二倍
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define mod1 1000000007
#define mod2 1000000009
#define endl '\n'
//#define int long long
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int N=5e5+10,P=131;
int n,m,a,b;
string s,s1,s2;
string c;
ull h[2*N],h1[2*N],h2[2*N],res;
ull p1[2*N],p2[2*N];
ull work(ull h[],int l,int r){
return h[r]-h[l-1]*p1[r-l+1];
}
bool get(int l,int r){
if(work(h,l,r)==res){
//cout<<l<<' '<<r<<" 1"<<endl;
return true;
}
if(work(h1,l,r)==res){
//cout<<l<<' '<<r<<" 2"<<endl;
return true;
}
if(work(h2,l,r)==res){
//cout<<l<<' '<<r<<" 3"<<endl;
return true;
}
return false;
}
void solve(){
cin>>s>>c>>a>>b;
n=s.size();
//构造串S1、S2
s1=s.substr(a)+s.substr(0,a);
reverse(s1.begin(),s1.end());
s2=s.substr(b)+s.substr(0,b);
reverse(s2.begin(),s2.end());
//求出每个串的hash值
s=s+s,s="#"+s;
s1=s1+s1,s1="#"+s1;
s2=s2+s2,s2="#"+s2;
c="#"+c;
h[0]=h1[0]=h2[0]=0;
p1[0]=1,p2[0]=1;
res=0;
for(int i=1;i<=2*n;i++){
p1[i]=p1[i-1]*P;
h[i]=h[i-1]*P+s[i]-'a'+1;
h1[i]=h1[i-1]*P+s1[i]-'a'+1;
h2[i]=h2[i-1]*P+s2[i]-'a'+1;
if(i<=n) res=res*P+c[i]-'a'+1;
}
//按照循环节来判断是否可以变成C
if(a<b) swap(a,b);
for(int i=1,j=1;j<=n;j++){
if(get(i,i+n-1)){
cout<<"yes"<<endl;
return ;
}
i=i+n-a+b;
if(i>=n+1) i=i%(n+1)+1;
}
for(int i=1,j=1;j<=n;j++){
if(get(i,i+n-1)){
cout<<"yes"<<endl;
return ;
}
i=i+a-b;
if(i>=n+1) i=i%(n+1)+1;
}
cout<<"no"<<endl;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
/*
1
abcde
abcde
1 2
*/