[HDU 4821] String (字符串哈希)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4821

题目大意:给你M,L两个字母,问你给定字串里不含M个长度为L的两两相同的子串有多少个?

哈希+枚举

我就是不会枚举这样的,这次涨姿势了。

每次枚举起点,然后就能枚举全部的。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <algorithm>
 6 #include <map>
 7 #include <set>
 8 using namespace std;
 9 typedef unsigned long long ull;
10
11 const ull B = 100*1000*1000+7;
12 int M,L;
13 char s[100010];
14 ull h[100010];
15 ull base[100010];
16 ull tt[100010];
17
18 int main(){
19     base[0] = 1;
20     for(int i=1;i<100010;i++) base[i] = base[i-1]*B;
21     while(scanf("%d%d",&M,&L)!=EOF){
22         memset(h,0,sizeof(h));
23         scanf("%s",s);
24         int len = strlen(s);
25         for(int i=0;i<len;i++){
26             if( i==0 ) h[i] = s[i];
27             else h[i] = h[i-1]*B + s[i];
28         }
29         int ans = 0;
30 //        printf("len = %d\n",len);
31         for(int i=0;i<L;i++){ // 枚举全部起点
32 //            puts("*******************");
33             int cnt = 0;
34             map<ull,int> H;
35             for(int j=i;j+L<=len;j+=L){ // 枚举每段
36                 tt[cnt++] = h[j+L-1] - (j==0?0:(h[j-1]*base[L]));
37 //                printf("%d => %llu\n",j,tt[cnt-1]);
38             }
39 //            printf("cnt=%d\n",cnt);
40             // 迟取法取每段然后数数,注意这里的j<min(cnt,M)
41             for(int j=0;j<min(cnt,M);j++){
42 //                printf("******%llu\n",H[tt[j]]);
43                 H[tt[j]]++;
44             }
45             if( H.size()==M ){
46                 ans++;
47 //                printf("%d==%d\n",H.size(),M);
48             }
49             for(int j=M;j<cnt;j++){
50                 H[tt[j-M]]--;
51                 if( H[tt[j-M]]==0 ) H.erase(tt[j-M]);
52                 H[tt[j]]++;
53                 if( H.size()==M ){
54                     ans++;
55 //                    printf("%d==%d\n",H.size(),M);
56                 }
57             }
58         }
59         printf("%d\n",ans);
60     }
61     return 0;
62 }
时间: 2024-10-30 22:50:01

[HDU 4821] String (字符串哈希)的相关文章

hdu 4821 String(字符串hash)

题目链接:hdu 4821 String 题意: 给你一个字符串,问你有多少子串,满足长度为m*len,并且这个子串能分成m个len长度的不同串. 题解: BKDRhash+map来判重.注意的是要以len长分类来扫,这样才不会超时. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace std; 4 typedef unsigned long long ull; 5 co

HDU 4821 String 字符串hash(水

题意: 给定整数M L 一个字符串s 我们定义一个子串为"好"串 iff 1.长度为 M*L 2.把这个好串分成M段,每段长度为L,且每段各不相同. 且我们得到的这些好串不重复计算(即把这些好串去重) 问有几个好串 #include <stdio.h> #include <cstring> #include <iostream> #include <map> using namespace std; typedef unsigned lo

HDU 3973 AC&#39;s String 字符串哈希

HDU 3973 通过哈希函数将一个字符串转化为一个整数,通过特定的方式可以使得这个哈希值几乎没有冲突(这就是关键之处,几乎没有视为没有= =!, 其实也可以考虑实现哈希冲突时的处理,只是这道题没必要而已),然后使用线段树维护修改后的哈希值. 因为输入的字符串只有26个,考虑使用一个大于等于26的素数p作为进制,然后将原串转化为一个p进制的数mod 2^63(也相当于自然溢出),然后这个数存入map中,然后使用线段树维护长串区间的哈希值,hash[l, r]表示将区间[l, r]的字符串转化为p

HDU 4821 String

String 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4821 题目大意: 给定一个字符串(最长10^5).从中选一个长度为 m * l 的子串,要求该子串能拆分为m个长度为 l 的一一不同的串.问有多少种取法. 解题思路: 比赛的时候,没有将串按照模 l 之后分类,导致TLE.. 字符串的哈希为:a[i] = a[i+1] * seek + str[i] - 'a' + 1; 那么j到j+len之间的字符串的哈希值是:a[j] - a[j+

[字符串hash] hdu 4821 String

题意: 给你M,L,再给一个串str 任意截取M*L长度的连续子串 再把这个子串分成M份长度为L的连续串 使得这M份互不相同 问有几种截取方法 思路: 考虑到子串是否相等,就运用字符串hash 用到map判重和割补的办法优化 代码: #include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"queue" #in

hdu 5510 Bazinga 字符串+哈希

Bazinga Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2078    Accepted Submission(s): 642 Problem Description Ladies and gentlemen, please sit up straight.Don't tilt your head. I'm serious.For

HDU 4821 String (HASH)

题意:给你一串字符串s,再给你两个数字m l,问你s中可以分出多少个长度为m*l的子串,并且子串分成m个长度为l的串每个都不完全相同 首先使用BKDRHash方法把每个长度为l的子串预处理成一个数字,接着根据题意直接map判重 BKDRHash:一种常用字符串hash,hash简单来说就是把一串字符串通过一些转化成为一个数字,并保证相同字符串转化的数字一样,不相同字符串转化的数字一定不一样.方法就是hash[i]=hash[i-1]*seed(进制)+str[i]-'a'+1(注意要加一,因为不

HDU 4821 杭州现场赛:每个片段字符串哈希比较

I - String Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4821 Description Given a string S and two integers L and M, we consider a substring of S as "recoverable" if and only if (i) I

HDU 2476 String painter(字符串转变)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2476 题意:给定两个长度相同的串A和B.每次操作可以将A的连续一段改变为另一个字母.求将A转换成B最少需要多少次操作? 思路:首先,我们假设没有A串,那么这就跟 BZOJ1260是一样的了,即答案为DFS(0,n-1)...但是这里有了A串就有可能使得操作次数更少.因为可能有些对应位置字母是相同的.我们设 ans[i]表示前i个字母变成一样的,那么若A[i]=B[i]则ans[i]=ans[i-1]