您也可以在我的个人博客中阅读此文章:跳转

题意

一个字符串S 问其中有几个子串能满足以下条件:
1、长度为m*l
2、可以被分成m个l长的不同的子串
问题就变成了如何快速的判断着m个子串是否存在相同的

思路与分析

这题我做了两天,用了四种不同的方法,从TL到WA再到AC。。。一路坎坷。
不过收获了很多东西,这题价值很大,堪称经典。
运用滑动窗口的思想,长度为m*l的为大窗,将其划分为m个长度为l的小窗。
枚举大窗的起点,以l为单位滑动大窗
直接将所有的子串存储起来会MLE,所以想到hash
将总串s hash,然后想办法快速的取出hash[s[i]~s[j]]
最终算法如下:

  1. 大窗起点
  2. 计算当前大窗口下m个小窗的hash值,扔到map里
  3. 对map里的元素个数进行统计,若为m,ans++
  4. 以l为单位滑动大窗,每滑动一次,map减掉一个出窗口的l串,加上一个刚刚进窗口的l串,若此时map.size()==m,ans++
  5. 大窗起点+1,返回1

    如何快速计算hash[s[i]~s[j]]

    方法1

    这里给出某大神的方法:

  6. base为基数,从S最后一个字符开始,hash[i]=hash[i+1]*base+str[i]-‘a’+1,即将i位以后的串hash成一个unsigned long long
  7. hash[s[i]~s[j]]的值即为: hash[i]-hash[j+1]*nbase[len].nbase[i]表示base的i次方
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    struct HashTab{
    ULL Has[1000005];
    ULL base=31;
    ULL nbase[1000005];
    void init(char *s){
    int len=strlen(s);
    for (int i=len-1;i>=0;i--) {
    Has[i]=Has[i+1]*base+s[i]-'a'+1;
    }
    nbase[0]=1;
    for (int i=1;i<=len;i++)
    nbase[i]=nbase[i-1]*base;
    return;
    }
    ULL getHash(LL l,LL r){//hashtab.getHash(l,r)表示返回s[l~r]的hash值
    int len=r-l+1;
    return Has[l]-Has[l+len]*nbase[len];
    }
    };

方法2

没看懂,直接给出函数吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct Hash{
LL B,mod,len,Has[1000005],Base[1000005];
void init(char *s,LL _B,LL _mod){
len=strlen(s);
B=_B; mod=_mod;
Base[0]=1; Has[0]=0;
for (LL i=1;i<=len;i++){
Base[i]=Base[i-1]*B%mod;
Has[i]=(Has[i-1]*B+s[i-1]-'a'+1)%mod;
}
return;
}
LL getHash(LL l,LL r){
//hashtab.getHash(l,r)表示返回s[l~r]的hash值
l++;r++;
return ((Has[r]-Has[l-1]*Base[r-l+1])%mod+mod)%mod;
}
};

主代码

写的时候要注意下表是否正确哇,边界处到底有没有=号等等。。不然debug的时候是真头疼

方法1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <map>
#include <cstring>
#include <cstdio>
#define ULL unsigned long long
#define LL long long
using namespace std;
map <ULL,int> mp;
struct HashTab{
ULL Has[1000005];
ULL base=31;
ULL nbase[1000005];
void init(char *s){
int len=strlen(s);
for (int i=len-1;i>=0;i--) {
Has[i]=Has[i+1]*base+s[i]-'a'+1;
}
nbase[0]=1;
for (int i=1;i<=len;i++)
nbase[i]=nbase[i-1]*base;
return;
}
ULL getHash(LL l,LL r){
int len=r-l+1;
return Has[l]-Has[l+len]*nbase[len];
}
};
HashTab _hash;
int main () {
int m,l;
char s[100010];
while (scanf("%d%d",&m,&l)!=EOF){
scanf("%s",s);
_hash.init(s);
int len=strlen(s);
int ans=0;
for (int i=0;i<l&&i+m*l-1<len;i++){
mp.clear();
for (int j=i;j<i+m*l;j+=l){//计算小窗
int tmp=_hash.getHash(j,j+l-1);
//cout<<j<<" "<<tmp<<endl;
mp[tmp]++;
}
if (mp.size()==m) ans++;
for (int j=i+m*l;j+l<=len;j+=l){//以l为单位滑动大窗口
int tmp=_hash.getHash(j-m*l,j-(m-1)*l-1);
//cout<<"-"<<j-m*l<<" "<<tmp<<endl;
mp[tmp]--;
if (mp[tmp]==0) mp.erase(tmp);
tmp=_hash.getHash(j,j+l-1);
//cout<<"+"<<j<<" "<<tmp<<endl;
mp[tmp]++;
if (mp.size()==m) ans++;
}
}
cout<<ans<<endl;
}
return 0;
}

方法2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <map>
#define MOD 1000000007
#define LL long long
using namespace std;
map <long long,int> mp;
struct Hash{
LL B,mod,len,Has[1000005],Base[1000005];
void init(char *s,LL _B,LL _mod){
len=strlen(s);
B=_B; mod=_mod;
Base[0]=1; Has[0]=0;
for (LL i=1;i<=len;i++){
Base[i]=Base[i-1]*B%mod;
Has[i]=(Has[i-1]*B+s[i-1]-'a'+1)%mod;
}
return;
}
LL getHash(LL l,LL r){
l++;r++;
return ((Has[r]-Has[l-1]*Base[r-l+1])%mod+mod)%mod;
}
}; Hash _hash;
int main () {
int m,l;
char s[100010];
while (scanf("%d%d",&m,&l)!=EOF){
scanf("%s",s);
_hash.init(s,131,MOD);
int len=strlen(s);
int ans=0;
for (int i=0;i<l&&i+m*l-1<len;i++){
mp.clear();
for (int j=i;j<i+m*l;j+=l){//计算小窗
int tmp=_hash.getHash(j,j+l-1);
//cout<<j<<" "<<tmp<<endl;
mp[tmp]++;
}
if (mp.size()==m) ans++;
for (int j=i+m*l;j+l<=len;j+=l){//以l为单位滑动大窗口
int tmp=_hash.getHash(j-m*l,j-(m-1)*l-1);
//cout<<"-"<<j-m*l<<" "<<tmp<<endl;
mp[tmp]--;
if (mp[tmp]==0) mp.erase(tmp);
tmp=_hash.getHash(j,j+l-1);
//cout<<"+"<<j<<" "<<tmp<<endl;
mp[tmp]++;
if (mp.size()==m) ans++;
}
}
cout<<ans<<endl;
}
return 0;
}

参考

  1. 高神 http://www.acmtime.com/?p=579
  2. http://blog.csdn.net/houserabbit/article/details/25740235

hdu4821 String的更多相关文章

  1. (通俗易懂小白入门)字符串Hash+map判重——暴力且优雅

    字符串Hash 今天我们要讲解的是用于处理字符串匹配查重的一个算法,当我们处理一些问题如给出10000个字符串输出其中不同的个数,或者给一个长度100000的字符串,找出其中相同的字符串有多少个(这样 ...

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

    http://acm.hdu.edu.cn/showproblem.php?pid=4821 昨晚卡了非常久,開始TLE,然后优化了之后,由于几个地方变量写混.一直狂WA.搞得我昨晚都失眠了,,. 这 ...

  3. 透过WinDBG的视角看String

    摘要 : 最近在博客园里面看到有人在讨论 C# String的一些特性. 大部分情况下是从CODING的角度来讨论String. 本人觉得非常好奇, 在运行时态, String是如何与这些特性联系上的 ...

  4. JavaScript String对象

    本编主要介绍String 字符串对象. 目录 1. 介绍:阐述 String 对象的说明以及定义方式. 2. 实例属性:介绍 String 对象的实例属性: length. 3. 实例方法:介绍 St ...

  5. ElasticSearch 5学习(9)——映射和分析(string类型废弃)

    在ElasticSearch中,存入文档的内容类似于传统数据每个字段一样,都会有一个指定的属性,为了能够把日期字段处理成日期,把数字字段处理成数字,把字符串字段处理成字符串值,Elasticsearc ...

  6. [C#] string 与 String,大 S 与小 S 之间没有什么不可言说的秘密

    string 与 String,大 S 与小 S 之间没有什么不可言说的秘密 目录 小写 string 与大写 String 声明与初始化 string string 的不可变性 正则 string ...

  7. js报错: Uncaught RangeError: Invalid string length

    在ajax请求后得到的json数据,遍历的时候chrome控制台报这个错误:Uncaught RangeError: Invalid string length,在stackoverflow查找答案时 ...

  8. c# 字符串连接使用“+”和string.format格式化两种方式

    参考文章:http://www.liangshunet.com/ca/201303/218815742.htm 字符串之间的连接常用的两种是:“+”连接.string.format格式化连接.Stri ...

  9. 【手记】注意BinaryWriter写string的小坑——会在string前加上长度前缀length-prefixed

    之前以为BinaryWriter写string会严格按构造时指定的编码(不指定则是无BOM的UTF8)写入string的二进制,如下面的代码: //将字符串"a"写入流,再拿到流的 ...

随机推荐

  1. 201521123005 《java程序设计》 第六周学习总结

    1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰,内容覆盖 ...

  2. Win8打开chm右侧空白解决方法

    Win8下打开CHM文件,左侧有目录,但是右侧空白.而且打开的时候,还弹出很多IE窗口. 感觉应该不是文件本身的问题.下面是我的解决方法,其他系统也可以试一试. 最初打开文件如下 首先:1,右键关联c ...

  3. 201521123112《Java程序设计》第12周学习总结

    1.本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2.书面作业 将Student对象(属性:int id, String name,int age,double ...

  4. phpcms总结(转)

    转自:http://www.cnblogs.com/zuzwn/p/3649536.html文件目录结构 根目录 | – api 接口文件目录 | – caches 缓存文件目录 | – config ...

  5. python实例编写(1)--浏览器操作,元素操作

    一.浏览器操作 1.  back()与 forward() #coding=gbk //编码不一定是utf-8 from selenium import webdriver //导入包,也叫”模组“ ...

  6. birt 集成到现有的web应用中

     我们已经有了一个Javaweb应用,现在要实现对报表的集成 我的应用是这个样子的  说明: 1)  这里使用的是birt4.4版本的, 下载birt-runtime-4.4.zip(在官方下载),然 ...

  7. vue+element搭建的后台管理系统

    最近工作不是很忙,自己在学习vue,在网上找了一个简单的项目练练手..... 这是本人的gitHub 上的项目地址:https://github.com/shixiaoyanyan/vue-admin ...

  8. 懒人小工具:T4自动生成Model,Insert,Select,Delete以及导出Excel的方法

    之前写了篇文章,懒人小工具:[自动生成Model,Insert,Select,Delete以及导出Excel的方法](http://www.jianshu.com/p/d5b11589174a),但是 ...

  9. mapreduce自定义排序(map端1.4步)

    3 3 3 2 3 1 2 2 2 1 1 1 -----------------期望输出 1 1 2 1 2 2 3 1 3 2 3 3 将以上数据进行排序,排序规则是:按照第一列升序排序,如果第一 ...

  10. [python学习笔记] 开篇

    今天开始学习markdown,立贴为证. 平均一天一小时.两个月先学完基础. 所有的帖子只为了学习记录,有不对的请提出,轻吐槽