1. 程式人生 > >HDU 4821 2013長春現場賽hash

HDU 4821 2013長春現場賽hash

turn cnblogs 時間 signed freopen log n) += 分析

題意:

一個字符串S 問其中有幾個子串能滿足以下條件:

1、長度為M*L

2、可以被分成M個L長的小串 每個串都不一樣

分析:

hash方法,一個種子base,打表出nbase[i]表示base的i次方

將以i位字符開頭之後的串hash成一個無符號長整型:hash[i]=hash[i+1]*base+str[i]-‘a‘+1

然後每個L長度的小串的hash值即為:hash[i]-hash[i+L]*nbase[L]

map記錄hash值的個數

以i位字符開頭的字符串與以i+L位字符開頭的字符串只相差兩個地方,減去hash[i ~ i+L],加上hash[i+M*L ~ i+(M+1)*L]

這樣算節省了很多時間

#include <bits/stdc++.h>
using namespace std;

typedef unsigned long long ull;
const int maxn=100005;
char str[maxn];
ull shash[maxn],nbase[maxn],base=31;
map<ull,int>mp;

int main()
{
//    freopen("in.txt","r",stdin);
    int M,L;
    nbase[0]=1;
    for(int i=1;i<maxn;i++)
        nbase[i]
=nbase[i-1]*base; while(~scanf("%d%d",&M,&L)) { scanf("%s",str); int n=strlen(str); shash[n]=0; for(int i=n-1;i>=0;i--) shash[i]=shash[i+1]*base+str[i]-a+1; int ans=0; for(int i=0;i<L && i+M*L<=n;i++) { mp.clear();
for(int j=i;j<i+M*L;j+=L) mp[shash[j]-shash[j+L]*nbase[L]]++; if(mp.size()==M) ans++; for(int j=i+L;j+M*L<=n;j+=L) { ull tmp=shash[j-L]-shash[j]*nbase[L]; mp[tmp]--; if(mp[tmp]==0) mp.erase(tmp); mp[shash[j+(M-1)*L]-shash[j+M*L]*nbase[L]]++; if(mp.size()==M) ans++; } } printf("%d\n",ans); } return 0; }

HDU 4821 2013長春現場賽hash