HDOJ--4821--String【字符串hash】

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

题意:给一个字符串,选m个长度为l的子串组成新的串,要求这m个子串互不相同,问有多少种组合。

字符串hash题目,以前没做过,做这道之前还用bkdrhash做了两道简单的题目,POJ1200和HDU1800。

用base数组记录乘了几个seed,base[i]表示seed^i,这个数组在之后计算子串hash值的时候会用到,先预处理一遍节省时间。

如果字符串从前往后hash,则hash[ i ] - hash[ i - l ] * base[ l ] 就是子串 [ i - l , i ] 的hash值,而从后往前hash的话 hash[ i ] - hash[ i + l ] * base[ l ] 就是子串 [ i , i + l ] 的hash值。

推导过程:以从前往后hash为例。假设字符串abab,子串长度2,则

i = 4时的hash值( ( ( (0+a)*seed+b ) * seed +a ) * seed + b ) ,

i - l = 2的hash值( (0+a)*seed+b ),乘base[2]之后 ( ( ( (0+a)*seed+b ) * seed  ) * seed  )

二者相减为a * seed + b,就是区间 [ i - l, i ] 对应字母 ab 的hash值。

之后按照每一点枚举m个l长度的子串,当他们hash值不同时就是一个结果。

#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 100010
#define eps 1e-7
#define INF 0x7FFFFFFF
#define seed 131
typedef long long ll;
typedef unsigned long long ull;

char s[MAXN];
ull base[MAXN],Hash[MAXN];
map<ull,int> mp;
int main(){
    int m,l,i,len,ans;
    base[0] = 1;
    for(i=1;i<MAXN;i++) base[i] = base[i-1] * seed;
    while(scanf("%d%d",&m,&l)!=EOF){
        scanf("%s",s);
        ans = 0;
        len = strlen(s);
        Hash[len] = 0;
        for(i=len-1;i>=0;i--){
            Hash[i] = Hash[i+1] * seed + s[i] - 'a';
        }
        for(i=0;i<l&&i+m*l<len;i++){
            mp.clear();
            for(int j=i;j<i+m*l;j+=l){
                ull temp = Hash[j] - Hash[j+l] * base[l];
                mp[temp]++;
            }
            if(mp.size()==m)    ans++;
            for(int j=i+m*l;j+l<=len;j+=l){
                ull temp = Hash[j-m*l] - Hash[j-(m-1)*l] * base[l];
                mp[temp]--;
                if(!mp[temp])   mp.erase(temp);
                temp = Hash[j] - Hash[j+l] * base[l];
                mp[temp]++;
                if(mp.size()==m)    ans++;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-10-12 03:24:58

HDOJ--4821--String【字符串hash】的相关文章

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

hdu4821 String 字符串hash(bkdrhash)

题意:给定m,l,一个字符串str. 我们定义一个子串为"recoverable"串 当 1.长度为 M*L 2.把这个好串分成M段,每段长度为L,且每段各不相同. 求"recoverable"串的个数,串相同位置不同也算不同. 思路:预处理数组hash,hash[i]表示从i位置到尾的字符串hash值.这里数组为unsigned long long型,因为可以自动取模.然后枚举 前l个位置,每次向后翻滚(将前一个长度为l的段hash值从map中去除,将翻滚后新出现

HDOJ 4821 String

字符串hash String Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 697    Accepted Submission(s): 190 Problem Description Given a string S and two integers L and M, we consider a substring of S as

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] 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 #inclu

hdu 4821 字符串hash+map判重 String (长春市赛区I题)

http://acm.hdu.edu.cn/showproblem.php?pid=4821 昨晚卡了非常久,開始TLE,然后优化了之后,由于几个地方变量写混.一直狂WA.搞得我昨晚都失眠了,,. 这几次hash军写错的变量--tmp=(j==m-1)?ah[j]:(ah[j]-ah[j-m]*base[m]);  外层循环变量是i,我写的字符串hash的几题都写成tmp=(i==0)? ah[j]:(ah[j]-ah[j-m]*base[m]); 二逼啊 题目大意: 给定一个字符串(最长10^

[字符串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

Acdreamoj1116(Gao the string!)字符串hash+二分+矩阵快速幂

Problem Description give you a string, please output the result of the following function mod 1000000007 n is the length of the string f() is the function of fibonacci, f(0) = 0, f(1) = 1... a[i] is the total number of times any prefix appear in the

HDU 4821 字符串hash

题目大意: 希望找到连续的长为m*l的子串,使得m个l长的子串每一个都不一样,问能找到多少个这样的子串 简单的字符串hash,提前预处理出每一个长度为l的字符串的hash值 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <map> 6 #include <set> 7 8 using na