2021杭电多校第八场 HDU7064-Singing Superstar(哈希)

简介: 2021杭电多校第八场 HDU7064-Singing Superstar(哈希)

传送门

题意:

给出一个长度为1 e 5的字符串和n ( n < = 1 e 5 )个长度< = 30的子串,求每个子串在模式串中的最大不相交出现次数;

思路:

大概是A C自动机模板题?

下面说一下哈希的做法:

有一个很重要的地方就是子串的长度是< = 30的,也就是说我们完全可以枚举模式串中长度为[ 1 , 30 ]的字符串,通过比较哈希值来看这段字符串是不是子串,时间复杂度大概O ( 30 n )

这样没有办法处理的问题就是如何保证不相交了。

设l a s [ x ]表示哈希值为x的字符串在模式串中的上一个出现位置(记录的是尾端字符所在的位置)。比如a b a b a b,当枚举到i = = 1的时候,子串为a b , l a s [ ′ a b ′ ] = 2

这样每次遍历的时候,只需要判断l a s [ n o w ] < i

简单说一下正确性,这样处理的目的是避免相交的子串,但是怎么能够保证这样是最优的呢?

如果有某个子串出现了奇数次,比如b a b a b a b,其中b a b出现了3次,按照上述算法,中间的b a b会被忽略掉,最后答案为2 次;

如果有某个子串出现了偶数次,比如b a b a b a b a b ,其中b a b 出现了4 次,按照上述算法,第二个和第四个的b a b会被忽略掉,最后答案为2次;

这两种都是最优的。

代码:

const int N=4e5+7,P=131;
ull h[N], p[N],a[N]; 
char str[N];
ull th[50],tp[50];
ull get(int l, int r)
{
    return h[r]-h[l-1]*p[r-l+1];
}
int main(){
    int _=read;
    while(_--){
        scanf("%s",str+1);
        p[0]=1;h[0]=0;
        int len=strlen(str+1);
        for(int i=1;i<=len;i++){
             h[i] = h[i - 1] * P + str[i];
             p[i] = p[i - 1] * P;
             //cout<<h[i]<<endl;
        }
        unordered_map<ull,int>mp,las;
        int n=read;
        rep(i,1,n){
            char s[35];cin>>s+1;
            tp[0]=1;th[0]=0;
            for(int j=1;j<=strlen(s+1);j++){
                th[j]=th[j-1]*P+s[j];
                tp[j]=tp[j-1]*P;
            }
            a[i]=th[strlen(s+1)];
            mp[a[i]]=0;
            las[a[i]]=0;
            //cout<<a[i]<<endl;
        }
        for(int i=1;i<=len;i++){
            for(int j=0;j<30&&i+j<=len;j++){
                ull now=get(i,i+j);
                //if(i==1&&j==2) cout<<now<<endl;
                if(mp.count(now)){
                    if(las[now]<i) mp[now]++,las[now]=i+j;
                }
            }
        }
        rep(i,1,n) printf("%d\n",mp[a[i]]);
    }
    return 0;
}


目录
相关文章
|
4月前
|
存储
【每日一题Day275】LC771宝石与石头 | 哈希表 状态压缩
【每日一题Day275】LC771宝石与石头 | 哈希表 状态压缩
39 0
|
4月前
|
存储 算法 C++
第 284 场周赛(C++ | 枚举 | 分类讨论 | 最短路 | 建反图)
【4月更文挑战第1天】- [LeetCode 6031](https://leetcode-cn.com/problems/find-all-k-distant-indices-in-an-array/):给定数组 `nums`、键值 `key` 和距离 `k`,找到所有与键值相等且与任意下标距离不超过 `k` 的下标,返回升序排序的列表。找到最小权重。
41 0
|
4月前
|
算法
2024春晚纸牌魔术原理----环形链表的约瑟夫问题
2024春晚纸牌魔术原理----环形链表的约瑟夫问题
|
4月前
【每日一题Day326】LC1222可以攻击国王的皇后 | 哈希表+模拟
【每日一题Day326】LC1222可以攻击国王的皇后 | 哈希表+模拟
33 0
|
4月前
【每日一题Day124】LC2347最好的扑克手牌 | 哈希表
【每日一题Day124】LC2347最好的扑克手牌 | 哈希表
30 0
|
11月前
|
算法
【算法挨揍日记】day03——双指针算法_有效三角形的个数、和为s的两个数字
【算法挨揍日记】day03——双指针算法_有效三角形的个数、和为s的两个数字
47 0
|
算法
《蓝桥杯每日一题》哈希·AcWing 2058. 笨拙的手指
《蓝桥杯每日一题》哈希·AcWing 2058. 笨拙的手指
61 0
|
机器学习/深度学习 人工智能
【第十五届蓝桥杯备赛(bushi,写文凑个数)】蓝桥OJ---排列序数
文章目录 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 三、知识风暴 DFS
90 0
|
存储
【每日一题Day95】LC1815得到新鲜甜甜圈的最多组数 | 状态压缩dp 记忆化搜索
子问题、哪些操作会影响数据:余下的甜甜圈数量left,以及剩余可以选的元素个数 cnt[x]【dfs函数的两个参数->使用状态压缩至一个int类型变量中】
106 0
【每日一题Day95】LC1815得到新鲜甜甜圈的最多组数 | 状态压缩dp 记忆化搜索
|
存储 算法 vr&ar
【力扣·周赛】第 284 场周赛(C++ | 枚举 | 分类讨论 | 最短路 | 建反图)
【力扣·周赛】第 284 场周赛(C++ | 枚举 | 分类讨论 | 最短路 | 建反图)
126 0
【力扣·周赛】第 284 场周赛(C++ | 枚举 | 分类讨论 | 最短路 | 建反图)