HDU4821 字串雜湊 尺取

2021-08-21 09:33:39 字數 1922 閱讀 4899

給你乙個字串s,問你滿足下面兩個條件的子串有多少個?

s長度不超過100000, $ 1\leq m * l \leq $ s的長度。

首先可以採用字串hash將字串處理便於儲存,字串hash我是在網上找的乙個方法,實際上是找乙個基數base,然後採用base進製,可以採用模乙個大質數,也可以是直接採用unsigned long long 爆了後自動模。這裡是採用 unsigned long long。此題可以記下字首hash值,之後如果要找區間[l,r]這個串的hash值,只需要hash[r] - hash[l - 1] * pow[r - l + 1]。這是因為對於乙個幾進製數,比如10進製的12345,現在我已經求得hash[1] = 1, hash[2] = 12, hash[3] = 123, hash[4] = 1234, hash[5] = 12345, 然後我想求[3,5]的hash值,那麼因為是10進製一眼可以知道是345,那麼計算機只能通過hash[5] - hash[2] * pow[3];而pow[3]即10的3次方,即為12345 - 12 × 1000 = 345,因此,可以知道其他進製也是滿足此公式。

處理完字串的hash之後,我首先想的是外層列舉i從 1~l

en−m

∗l+1

1~len - m * l + 1

1~len−

m∗l+

1, 然後內層列舉從i開始,m個長度為l的串是否有重複值,如果沒有答案就++,之後就tle,其實複雜度是 (le

n−m∗

l+1)

∗m

(len - m * l + 1)*m

(len−m

∗l+1

)∗m * map(log), tle也確實正常。之後才知道i只需要列舉從1~l

1~l1~

l就行,然後內層列舉所有的長度為l的子串,並將它們的hash順序存入陣列,之後採用尺取法,每m個看是否有m個不同的元素,如果是則答案++,此複雜度就到了o(l

∗len

/l)∗

log(

ull)

o(l * len / l) * log(ull)

o(l∗le

n/l)

∗log

(ull

)即為o(l

en∗l

og

)o(len * log)

o(len∗

log)

#include

#include

#include

#include

#include

#include

#include

using

namespace std;

typedef

unsigned

long

long ull;

const

int maxn =

100000

;const ull base =

233ull

;ull hash[maxn +5]

, pow[maxn +5]

;ull num[maxn +5]

;mapint>vis;

char s[maxn +5]

;int m, l, tot, res;

ull get_hash

(int l,

int r)

void

solve()

if(cnt == m)res++

;int r = m +

1, l =1;

while

(r <= tot)

}int

main()

printf

("%d\n"

, res);}

return0;

}

另外基數base要大於s[i],即滿足進製規則。

HDU 4821 String(字串雜湊)

傳送門 題目大意就是給你乙個字串,然後問你在這個字串裡有多少個長度為m l m lm l 的子串,並且這連續的 m mm 個長度為 l ll 的子串還要相互不一樣。直接h as hhash hash 選取乙個起始位置 1 l 1 l 1 l 然後每 l ll 個 has hhash hash 一下,...

hdu2920 字串雜湊

模式串中 把它分成一截截,當某一截在s串中多個位置能找到匹配,找第乙個匹配點,貪心 因為當中間有 可以利用它跳過一些字元,當遇到 先跳過乙個字元,其他的一截截貪心去找到匹配位置,若最後剩餘偶數個字元,則match 第一截和最後一截如果是非 和 必須嚴格匹配 找來的雜湊寫法 include inclu...

HDU 1800 字串雜湊

從n個數中,最少能分出幾個單調遞增序列。水題。就是找到n個數中出現次數最多的次數。只是n個數範圍有30個十進位制位,需要當成字串處理,這就用到了字串雜湊。include using namespace std const int maxn 3005 const int mod 100007 stru...