日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

jzoj5462

發布時間:2025/3/15 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 jzoj5462 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題意求長度為n的字符串中的長度為m的連續子串有多少個是不同的。

比如n=5, s=aaaab

它長度為3的子串有

aaa、aaa、aab

有兩個不同的子串,答案為2。

解法有兩種,其一是hash,其二是后綴自動機。

這里講講hash。

我用的雙hash。

大意就是第一個hash用來查詢,第二個hash用來判第一個hash的沖突(沖突的概率極小)

hash的寫法:

預處理:

h1[0] = h2[0] = 0;for (int i = 1; i <= len; i++){h1[i] = (h1[i - 1] * 131 + s[i]) % m1;h2[i] = (h2[i - 1] * 97 + s[i]) % m2;}

求出每個子串的hash值:

for (LL i = 1; i <= len - m + 1; i++){LL k1 = ((h1[i + m -1] - h1[i - 1] * ksm(131, m, m1)) % m1 + m1) % m1;LL k2 = ((h2[i + m -1] - h2[i - 1] * ksm(97, m, m2)) % m2 + m2) % m2;hash(k1, k2);}

如上圖所示

最后統計答案:

void add(LL k1, LL k2) {a[tot].x = k2;a[tot].next = h[k1];h[k1] = tot++; }void hash(LL k1, LL k2) {for (LL i = h[k1]; ~i; i = a[i].next)if (a[i].x == k2)return;add(k1, k2);ans++; }

如果發現兩個hash值都不同,則說明是一個新的子串。

完整代碼:

#include <cstdio> #include <cstring> #define LL long long using namespace std;const LL maxn = 200005, m1 = 999973, m2 = 1000000000 + 9;LL n, m, ans, tot;LL h[m1 + 5], h1[maxn], h2[maxn];char s[maxn];struct node {LL x, next; }a[maxn];void add(LL k1, LL k2) {a[tot].x = k2;a[tot].next = h[k1];h[k1] = tot++; }void hash(LL k1, LL k2) {for (LL i = h[k1]; ~i; i = a[i].next)if (a[i].x == k2)return;add(k1, k2);ans++; }LL ksm(LL a, LL b, LL mo) {LL ans = 1, base = a;while (b){if (b & 1)ans = (ans * base) % mo;base = (base * base) % mo;b >>= 1;}return ans % mo; }int main() {freopen("article.in","r",stdin);freopen("article.out","w",stdout);ans = tot = 0;memset(h, -1, sizeof h);scanf("%lld%lld", &n, &m);scanf("%s", s + 1);LL len = strlen(s + 1);h1[0] = h2[0] = 0;for (int i = 1; i <= len; i++){h1[i] = (h1[i - 1] * 131 + s[i]) % m1;h2[i] = (h2[i - 1] * 97 + s[i]) % m2;} for (LL i = 1; i <= len - m + 1; i++){LL k1 = ((h1[i + m -1] - h1[i - 1] * ksm(131, m, m1)) % m1 + m1) % m1;LL k2 = ((h2[i + m -1] - h2[i - 1] * ksm(97, m, m2)) % m2 + m2) % m2;hash(k1, k2);}printf("%lld\n", ans);return 0; } View Code

?P.S.:

這題我使用的是哈希表的方法,要求m1一定要比較小,m2不能取太大,否則后來的運算中可能會出現溢出的情況。

我一般取m1=999973,m2=1e9+9

這里還有另外一種方法。

我們把每次hash得到的兩個數k1,k2,搞成一個pair。

然后把pair塞進一個vector中,排序并去重之,如此可以直接得到答案。

核心代碼:

h1[0] = h2[0] = 0;for (int i = 1; i <= len; i++){h1[i] = (h1[i - 1] * 131 + s[i]) % m1;h2[i] = (h2[i - 1] * 97 + s[i]) % m2;} for (LL i = 1; i <= len - m + 1; i++){LL k1 = ((h1[i + m -1] - h1[i - 1] * ksm(131, m, m1)) % m1 + m1) % m1;LL k2 = ((h2[i + m -1] - h2[i - 1] * ksm(97, m, m2)) % m2 + m2) % m2;v.push_back(make_pair(k1, k2));}sort(v.begin(), v.end());ans = unique(v.begin(), v.end()) - v.begin();printf("%lld\n", ans);

?PSS:

之前寫的hash方法太慢,現在使用新的hash方法,大大提高了速度。(from O(nm) to O(n))

轉載于:https://www.cnblogs.com/yohanlong/p/7804699.html

總結

以上是生活随笔為你收集整理的jzoj5462的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。