2019 多校4 Hidden Anagrams(hash)

   题意就是给你s1和s2,然后让你求最长的公共子串,这里的公共子串是只要s1和s2里出现了2个各字母出现次数均相等的子串,就可以认为这是公共子串了。

  这题我一开始用的是二分,结果一直wa,后面看了这组数据(iamaweakishspeller  ,williamshakespeare)这组数据正确应该输出18的,但是我二分的mid在9就不行了,然后就可以知道较大规模虽然满足,但是小规模却不满足,如果能用二分的话应该是大规模满足,则小规模必满足的,所以的话这题就没有单调性,就不能用二分了。然后换种思路用hash了,但是普通的hash的话,ab对应的hash值和ba对应的是不同的,因为普通的hash方法是考虑了顺序在里面了,所以我们要消去顺序的影响,那就是把每个串的26个字母出现的个数都求出来,用来hash,我用的是自然溢出法,不用自然溢出法总是wa。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
const ull base=90;
int pre1[4005][26],pre2[4005][26];
string s1,s2;
unordered_map<ull,bool>mp;

int main()
{
    int len1,len2;
    ull ihash;
    cin>>s1>>s2;
    len1=s1.size();
    len2=s2.size();
    s1=" "+s1;
    s2=" "+s2;
    for(int i=1;i<=len1;i++)
    {
        for(int j=0;j<=25;j++)
            pre1[i][j]=pre1[i-1][j];
        pre1[i][s1[i]-'a']++;
    }
    for(int i=1;i<=len2;i++)
    {
        for(int j=0;j<=25;j++)
            pre2[i][j]=pre2[i-1][j];
        pre2[i][s2[i]-'a']++;
    }
    for(int len=min(len1,len2);len>=1;len--)
    {
        mp.clear();
        for(int st=1;st<=len1-len+1;st++)
        {
            int ed=st+len-1;
            ihash=0;
            for(int i=0;i<26;i++)
                ihash=ihash*base+(pre1[ed][i]-pre1[st-1][i]);
            mp[ihash]=1;
        }
        for(int st=1;st<=len2-len+1;st++)
        {
            int ed=st+len-1;
            ihash=0;
            for(int i=0;i<26;i++)
                 ihash=ihash*base+(pre2[ed][i]-pre2[st-1][i]);
            if(mp.count(ihash))
            {
                printf("%d
",len);
                return 0;
            }
        }
    }
    printf("0
");
    return 0;
}
原文地址:https://www.cnblogs.com/eason9906/p/11754784.html