hdu 4821 String(枚举 + 字符串hash)

题意:给两个整数L,M和一个字符串,问这个字符串有多少个满足要求的子串。要求有两个:①子串的长度为L*M

②把子串分为M个长度为L的串以后,这些串不能有两个完全一样的串。

思路:这题当年读了整场也没读懂啊(哭),今天也读了好一会儿才反应过来T^T,真是不愉快。。。读懂题以后就很水了,通过字符串hash,可以很轻松地求出任意一个长度为L的子串的hash值。枚举字符串起始位置,这个从0枚举到L-1,然后,在这个位置开始,每L个字符作为一块,首先将前M块插入到map中,同时维护存在相同字符串的个数,如果这个数量为0,那么显然是满足要求的。接下来,将这个区间向右移,删掉第1块,加入第M+1块,同样维护那个值,这样都枚举一遍就行了~


代码:


#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-8
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
typedef unsigned long long Ull;
const int mx = 233;
const int maxn = 100000+10;
char str[maxn];
Ull H[maxn],x[maxn];
map<Ull,int>mp;
inline Ull getval(int s,int len)
{
    return H[s] - H[s+len]*x[len];
}
int main()
{
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
    x[0] = 1;
    for(int i = 1;i < maxn;++i) x[i] = x[i-1]*mx;
    int M,L;
    while(~scanf("%d%d",&M,&L))
    {
        scanf("%s",str);
        int n = strlen(str);
        H[n] = 0;
        for(int i = n - 1;i >= 0;--i)
            H[i] = H[i+1]*mx + str[i] - 'a';
        Ull tval;
        int v,ans = 0;
        for(int i = 0;i < L;++i)
        {
            if(i + M*L > n) break;
            mp.clear();
            int s = i, t = i + (M-1)*L;
            int cnt = 0;
            for(int j = s;j <= t; j += L)
            {
                tval = getval(j,L);
                if(mp.find(tval) == mp.end())
                    mp[tval] = 1;
                else
                {
                    v = mp[tval];
                    if(v == 1) cnt++;
                    mp[tval]++;
                }
            }
            if(cnt == 0) ans++;
            while(t + 2*L <= n)
            {
                tval = getval(s,L);
                v = mp[tval];
                if(v > 2) mp[tval]--;
                else if(v == 2) cnt--,mp[tval]--;
                else mp.erase(tval);
                s += L;
                tval = getval(t+L,L);
                if(mp.find(tval) == mp.end())
                    mp[tval] = 1;
                else
                {
                    v = mp[tval];
                    if(v == 1) cnt++;
                    mp[tval]++;
                }
                t += L;
                if(cnt == 0) ans ++;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值