給你乙個字串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...