智算之道-字符串

智算之道-字符串_第1张图片
思路
直接枚举字符串S全排列显然复杂度不允许,考虑到字符只有26种,那么我们考虑贡献。
直接去枚举字符串T长度为strlen(S)的字串,看对应的字符串S的每种字符个数是否一样。
一样的话,看这个子串是不是被计算过,没被计算过,对答案贡献就加1。对于是否贡献过,我们可以用map来存字符串是否出现过,直接存字符串比较耗时,所以可以先对字符串哈希,存字符串的哈希值即可。

#include
using namespace std;
typedef unsigned int ll;
const int N=3e6+5;
char a[N],b[N];
ll base=131,has[N],h[N];
map<ll,bool>mp;
int cnt[130];
int q[130];
int main()
{
    has[0]=1;
    for(int i=1;i<=200000;i++) has[i]=has[i-1]*base;
    scanf("%s",b);
    scanf("%s",a);
    int lb=strlen(b);
    int la=strlen(a);
    for(int i=0;i<la;i++){
        if(i==0) h[i]=a[i]-'a';
        else h[i]=h[i-1]*base+a[i]-'a';
    }
    if(lb>la){
        printf("0");
         return 0;
    }
    for(register int i=0; b[i]; ++i)
        cnt[b[i]]++;
    int num=0;
    for(register int i=0; i<lb; ++i)
        q[a[i]]++;
    int flag=0;
    for(register int i='a'; i<='z'; ++i)
    {
        if(q[i]!=cnt[i])
        {
            flag=1;
            break;
        }
    }
    if(!flag)
    {
        ll k=h[lb-1];
        ++num;
        mp[k]=1;
    }
    for(register int i=lb; i<la; ++i)
    {
        q[a[i]]++;
        q[a[i-lb]]--;
        int flag=0;
        for(register int j='a'; j<='z'; ++j)
        {
            if(q[j]!=cnt[j])
            {
                flag=1;
                break;
            }
        }
        if(!flag)
        {
            ll k=h[i]-h[i-lb]*has[lb];
            if(!mp[k])
            {
                mp[k]=1;
                ++num;
            }
        }
    }
    printf("%d",num);

    return 0;
}

你可能感兴趣的:(思维,哈希)