其他分享
首页 > 其他分享> > L.Let's Swap 找规律+字符串双哈希

L.Let's Swap 找规律+字符串双哈希

作者:互联网

(这道题赛后补的,就是说现场根本没有时间开到www

依据题意,有两种操作,过程还蛮复杂的,又倒置又反转,然后我看到这种操作一般就懵逼了,然后捏?

这时候一般就需要手%啥的,就是画图模拟,找规律,一般都有一些”性质“的

比如这题的一些性质:

#同一个操作使用两次,会撤销,相当于没有操作

那么..设想操作A,B组成了一个序列,这个序列只能是:

ABABABA....

BABABAB....

#那么AB操作,实质上是什么呐?

画图可知,一次ab或者ba,相当于把字符串向左或者向右移动 abs(L1-L2),若干次操作ab(ba),相当于把字符串向左或者向右移动若干次

题解在这边写的是d=gcd(s.length(),L1-L2),最多位移n/d次,在这边看了好久,自己推了一下应该是因为:

 

 

那么我们就可以判断T是否是S经过若干次位移得到的——用kmp或者字符串哈希

kmp(这玩意学一次忘一次,每次用到都得重新学x,干脆写Hash:

字符串Hash的思想要是不明白的话左转某谷或者某dn哇~

想记录一下实现的细节:

比如要把T扩展成2倍,因为我们肯定要涉及到末尾取一部分+前面的一部分合并起来,展开成两倍可以实现

然后循环n次(最多位移n次吧,不过这个应该是为了保证不错,有往上放大过的数值了),判断Hash值相等不相等~

又因为有B(AB)(AB)(AB)

或者A(AB)(AB)(AB)

或者(AB)(AB)S

三种情况分别试一下

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
const long long mod=1e9+7;
string s,t,tmp;
long long ss[maxn],ss1[maxn],tt[maxn],tt1[maxn],p[maxn],p1[maxn];
int len,totlen,l1,l2;
bool check( )
{

    for(int i=0;i<totlen;i++){
        ss[i+1]=(ss[i]*31%mod+(tmp[i]-'a'+1)%mod+mod)%mod;
        ss1[i+1]=(ss1[i]*29%mod+(tmp[i]-'a'+1)%mod+mod)%mod;
    }
    //double hash 


    int cnt=totlen,pos=totlen,flag=0;
    
        //最多移位n次,这里有点暴力枚举了 
        while(cnt){
            pos%=2*totlen;
            while(pos<totlen) pos+=len;
        
            if((tt[pos]-tt[pos-totlen]*p[totlen]%mod+mod)%mod==ss[totlen]&&
               (tt1[pos]-tt1[pos-totlen]*p1[totlen]%mod+mod)%mod==ss1[totlen])
               {
                    flag=1;break;
               }
            pos+=len;
            cnt--;
        } 
        return flag;
}
void solve(){
    //ababab,delta=gcd(l1-l2)
    totlen=s.length();
    len=abs(l1-l2);
    
    t=t+t;
    
    for(int i=0;i<2*totlen;i++){
        tt[i+1]=(tt[i]*31%mod+(t[i]-'a'+1)%mod+mod)%mod;
        tt1[i+1]=(tt1[i]*29%mod+(t[i]-'a'+1)%mod+mod)%mod;
    }
    
    tmp=s;

    if(    check() ) {
        cout<<"yes"<<endl;
        return;
    }
    
    tmp=s.substr(l1)+s.substr(0,l1);
    reverse(tmp.begin(),tmp.end());

    if(    check() ) {
        cout<<"yes"<<endl;
        return;
    }
    
    
    tmp=s.substr(l2)+s.substr(0,l2);
    reverse(tmp.begin(),tmp.end());

    if(    check() ) {
        cout<<"yes"<<endl;
        return;
    }
    
    cout<<"no"<<endl;
    return;
}
int main()
{
    //freopen("lys.in","r",stdin);
    
    p[0]=1;p1[0]=1;
    for(int i=1;i<maxn-2;i++)
    {
        p[i]=p[i-1]*31%mod;p1[i]=p1[i-1]*29%mod;
    }
    
    
    int q;
    cin>>q;
    while(q--){
        cin>>s;
        cin>>t;
        cin>>l1>>l2;
        solve();
    }
}

 

标签:AB,或者,long,maxn,Swap,哈希,操作,字符串,Let
来源: https://www.cnblogs.com/liyishui2003/p/16478973.html