Mail.Ru Cup 2018 Round 3 E. Check Transcription (字符串hash)

Mail.Ru Cup 2018 Round 3 E. Check Transcription

  • 题意:给你一个\(01\)\(s\)和一个字符串\(t\),将\(t\)中的两个不同的子串映射成\(0\)\(1\),问你有多少种不同的映射方法使得\(s\)映射后刚好为\(t\)

  • 题解:先统计\(0\)\(1\)的个数\(cnt0\)\(cnt1\),假设我们映射给\(0\)的长度为\(len_0\)\(1\)\(len_1\),有:\(cnt_0*len_0+cnt_1*len_1=|t|\),可以枚举\(len_0\)的长度,如果合法,就能得到\(len_1\)的长度,同时也自然能得到两个映射的子串,用hash去暴力check是否合法.显然这种方法看上去并没有问题,我们担心的是会不会超时.设\(c=max(cnt_0,cnt_1)\),显然\(c\ge \frac{|s|}{2}\),根据上面的公式,合法的解最多有\(\frac{|t|}{c}\)个,所以最多跑\(|t|+\frac{|t|}{c}*|s|=|t|+2*|t|\)次,前面的这个\(|t|\)应该可以优化掉,但我直接跑了,问题不大,此外这题hash自然溢出会被卡,记得取模

  • 代码

    #include <bits/stdc++.h>
    #define ll long long
    #define ull unsigned long long 
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e7 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
     
    int n,m;
    int cnt0,cnt1;
    string s,t;
    ll ans=0;
    ull base=19260817;
    ull h[N],p[N];
     
    void init(){
        p[0]=1,h[0]=0;
        for(int i=1;i<=m;++i){
            h[i]=(h[i-1]*base+t[i])%mod;
            p[i]=p[i-1]*base%mod;
        }
    }
     
    ull get_hash(int l,int r){
        return (h[r]-h[l-1]*p[r-l+1]%mod+mod)%mod;
    }
     
    int main() {
        cin>>s>>t;
        n=(int)s.size(),m=(int)t.size();
        s=" "+s,t=" "+t;
        init();
        for(int i=1;i<=n;++i){
            if(s[i]=='0'){
                cnt0++;
            }
            else{
                cnt1++;
            }
        }
        for(int i=1;i<=m;++i){
            int len0=i;
            if(m-cnt0*len0<=0) break;
            if((m-cnt0*len0)%cnt1==0){
                int len1=(m-cnt0*len0)/cnt1;
                ull res0=0,res1=0;
                string now0,now1;
                int now=1;
                for(int j=1;j<=n;++j){
                    if(s[j]=='0'){
                        if(!res0) res0=get_hash(now,now+len0-1);
                        now+=len0;
                    }
                    else{
                        if(!res1) res1=get_hash(now,now+len1-1);
                        now+=len1;
                    }
                }
                if(res0==res1) continue;
                bool flag=true;
                int pos=1;
                for(int j=1;j<=n;++j){
                    if(s[j]=='0'){
                       ull cur=get_hash(pos,pos+len0-1);
                       if(cur!=res0){
                           flag=false;
                           break;
                       }
                       pos=pos+len0;
                    }
                    else{
                        ull cur=get_hash(pos,pos+len1-1);
                        if(cur!=res1){
                            flag=false;
                            break;
                        }
                        pos=pos+len1;
                    }
                }
                if(flag) ans++;
            }
        }	
        cout<<ans<<endl;
        return 0;
    }
    
原文地址:https://www.cnblogs.com/lr599909928/p/15572592.html