HDU 4821 String

String

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 451    Accepted Submission(s): 123


Problem Description
Given a string S and two integers L and M, we consider a substring of S as “recoverable” if and only if
  (i) It is of length M*L;
  (ii) It can be constructed by concatenating M “diversified” substrings of S, where each of these substrings has length L; two strings are considered as “diversified” if they don’t have the same character for every position.

Two substrings of S are considered as “different” if they are cut from different part of S. For example, string "aa" has 3 different substrings "aa", "a" and "a".

Your task is to calculate the number of different “recoverable” substrings of S.
 

Input
The input contains multiple test cases, proceeding to the End of File.

The first line of each test case has two space-separated integers M and L.

The second ine of each test case has a string S, which consists of only lowercase letters.

The length of S is not larger than 10^5, and 1 ≤ M * L ≤ the length of S.
 

Output
For each test case, output the answer in a single line.
 

Sample Input
  
  
3 3 abcabcbcaabc
 

Sample Output
  
  
2

题目大意:

给你一个m以及l   表示m段l长的字符串

然后继续给出一段字符串s其长度是大于m*l

问这段字符串s可以分成几个长度为m*l的部分使得这一段m*l中m段字符串都不相同

EG:

(abc abc bca)这一个例子就不行,前两个相同

(bca bcb caa)这一个例子就可以

(cab cbc aab)这一个例子也可以

(abc bca abc)这一个例子不行,第一个和最后一个相同

  所以最后的答案是2

最开始看见题目就被巨大的数据量所吓倒...... 赛后听别人说是字符串hash,参考以下资料https://www.byvoid.com/blog/string-hash-compare/

 关键点在于seek的选择必须是正数,其次要用到unsigned long long (超数据范围会自动 取模)

我先取0~l之间的哈希值 然后 l到2*l 其次2*l到3*l 直到(m-1)*l到m*l 分别算出hash值,存进map里面,其对应的int值++,这时如果map.size()==m 则说明这m个字符串都不相同,ans++

这时就是另外一个亮点了.....其次对于m*l到len的处理 

 for(int j=i+m*l;j+l<=len;j+=l)
            {
                tmp=hh[j-m*l]-hh[j-(m-1)*l]*base[l];
                mp[tmp]--;
                if(!mp[tmp]) mp.erase(tmp);
                tmp=hh[j]-hh[j+l]*base[l];
                mp[tmp]++;
                if(mp.size()==m) ans++;
            }
先是减去m*l的前一个字符串的长l 从map中也要减去,此时如果mp[tmp]==0 就删掉这个tmp 后面就是把m*l的后一个字符串长l的加入map中  继续判断,

这一步的优化省了很多时间。

#include<iostream>
#include<stdio.h>
#include<map>
#include<cstring>
using namespace std;
#define ULL unsigned long long
#define maxn 100005
#define seek 131

/*
字符串的hash为a[i] = a[i+1] * seek + str[i] - 'a' + 1;
base[i] = seek^i;
j到j+len之间的字符串的哈希值是:a[j] - a[j+L]*base[L];
*/

map<ULL,int> mp;
char s[maxn];

ULL  base[maxn],hh[maxn]; // ULL函数会在超过其最大值之后自动取模


int main ()
{
    int m,l,len;
    base[0]=1;
    for (int i = 1; i < maxn; i++) base[i] = base[i - 1] * seek;
    while(~scanf("%d%d%s", &m, &l, &s))
    {
        len=strlen(s);
        hh[len]=0;
        int ans=0;
        for(int i=len-1;i>=0;i--)
        hh[i]=hh[i+1]*seek+s[i]-'a';

        for(int i=0;i<l&&i+m*l<=len;i++)
        {
            mp.clear();
            ULL tmp;
            //cout<<" 2333333 \n";
            for(int j=i;j<i+m*l;j+=l)
            {
                //cout<<j<<endl;
                tmp=hh[j]-hh[j+l]*base[l];
                mp[tmp]++;
            }

            if(mp.size()==m) ans++;

            for(int j=i+m*l;j+l<=len;j+=l)
            {
                tmp=hh[j-m*l]-hh[j-(m-1)*l]*base[l];
                mp[tmp]--;
                if(!mp[tmp]) mp.erase(tmp);
                tmp=hh[j]-hh[j+l]*base[l];
                mp[tmp]++;
                if(mp.size()==m) ans++;
            }
        }
        printf("%d\n",ans);
    }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值