zoukankan      html  css  js  c++  java
  • 牛客-白兔的字符串(Hash+二分)

    题目链接:https://ac.nowcoder.com/acm/problem/15253

    题目描述

    白兔有一个字符串T。白云有若干个字符串S1,S2..Sn。

    白兔想知道,对于白云的每一个字符串,它有多少个子串是和T循环同构的。

    提示:对于一个字符串a,每次把a的第一个字符移动到最后一个,如果操作若干次后能够得到字符串b,则a和b循环同构。

    所有字符都是小写英文字母

    输入描述:
    第一行一个字符串T(|T|<=10^6)
    第二行一个正整数n (n<=1000)
    接下来n行为S1~Sn (|S1|+|S2|+…+|Sn|<=107),max(|S1|,|S2|,|S3|,|S4|,..|Sn|)<=106
    输出描述:
    输出n行表示每个串的答案

    输入
    abab
    2
    abababab
    ababcbaba

    输出
    5
    2

    既然是循环同构,那么我们可以将串T展开成2|T|的长度,然后用Hash保存每种T长度下的值,接下来我们在遍历以下n个字符串的时候可以直接查找上面是否出现了字符串,如果有的话那么ans++,至于查找的方式,用map的话比较慢,会T掉,用二分就可以了(我们先排好序),实际上极限的理论复杂度是(O(log|T|sum S)),也会T掉的。。。只不过很少有代码会跑到这种极限复杂度的。

    以下是AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef unsigned long long ull;
    const int mac=2e6+10;
    
    char ss[mac],s[mac];
    ull hashs[mac],wei[mac];
    int base=131;
    
    int main()
    {
        scanf ("%s",ss);
        int len=strlen(ss);
        for (int i=0; i<len; i++)
            ss[len+i]=ss[i];
        ull hash=0,cnt=0;
        wei[0]=1;
        for (int i=1; i<mac; i++)
            wei[i]=wei[i-1]*base;
        int num=0;
        for (int i=0; i<len*2-1; i++){
            hash=hash*base+ss[i];
            cnt++;
            if (cnt==len){
                cnt--;
                hashs[++num]=hash;
                hash=hash-wei[len-1]*ss[i-len+1];
            }
        }
        sort(hashs+1,hashs+num+1);
        int n;
        scanf ("%d",&n);
        for (int i=1; i<=n; i++){
            scanf ("%s",s);
            int lens=strlen(s);
            int ans=0;
            hash=0,cnt=0;
            for (int i=0; i<lens; i++){
                hash=hash*base+s[i];
                cnt++;
                if (cnt==len){
                    cnt--;
                    int pos=lower_bound(hashs+1,hashs+num+1,hash)-hashs-1;
                    if (pos<num && hashs[pos+1]==hash) ans++;
                    hash=hash-wei[len-1]*s[i-len+1];
                }
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    
    路漫漫兮
  • 相关阅读:
    Android 学习笔记5程序开发模式&拨号器&短信发送器小例程
    Android学习笔记6日志输出&单元测试
    utkernel 移植时调试方法
    在eclipse中查看Android SDK源代码
    (转载)怎样改进数据库的查询性能?
    asp.net 编程模型
    数据回传
    在博客园记录我的成长
    LeetCode14.最长公共前缀
    LeetCode206.反转链表
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/13370585.html
Copyright © 2011-2022 走看看