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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

BZOJ 4566 [Haoi2016]找相同字符

發(fā)布時(shí)間:2024/1/18 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 BZOJ 4566 [Haoi2016]找相同字符 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

后綴數(shù)組 或 后綴自動(dòng)機(jī)

后綴數(shù)組的做法 O(nlogn) : 串接起來(lái)。要求的就是后綴數(shù)組中不屬于同一串的后綴的LCP。暴力做 O(n2) 。發(fā)現(xiàn)我們一直都在區(qū)間取min,插一個(gè)線段樹,每次找出最小的然后分兩邊做即可。(從大到小做,用并查集維護(hù)也很好)。這個(gè)方法復(fù)雜度不是很優(yōu)秀,SA常數(shù)比較大,需要一個(gè)SA的優(yōu)化技巧 if(m >= n) break; 即如果已經(jīng)排完了就沒(méi)必要繼續(xù)了。不加可能會(huì)T。

后綴自動(dòng)機(jī)做法 O(n) : 建廣義SAM。一個(gè)節(jié)點(diǎn)代表的子串的貢獻(xiàn)就是(len[i]-len[fail[i]]) * sz[i][0] * sz[i][1]。即節(jié)點(diǎn)代表的串?dāng)?shù)量 * 在串1中出現(xiàn)次數(shù) * 在串2中出現(xiàn)次數(shù)。

以下后綴數(shù)組做法,自動(dòng)機(jī)的還沒(méi)寫。

#include<cstdio> #include<cstring> #include<algorithm> #define N 400005 using namespace std; namespace runzhe2000 {typedef long long ll;ll ans;int n1, n2, s[N], n, t1[N], t2[N], sum[N], height[N], sa[N], rank[N];struct item{int l, r;}q[N];char s1[N], s2[N];struct seg{int mi, mipos, cnt1, cnt2;}t[N*5];void build(int x, int l, int r){if(l == r){t[x].mi = height[l];t[x].mipos = l;if(sa[l] <= n1) t[x].cnt1 = 1, t[x].cnt2 = 0;else if(n1+2 <= sa[l]) t[x].cnt1 = 0, t[x].cnt2 = 1;else t[x].cnt1 = t[x].cnt2 = 0;return;}int mid = (l+r)>>1;build(x<<1,l,mid); build(x<<1|1,mid+1,r);if(t[x<<1].mi < t[x<<1|1].mi) t[x].mi = t[x<<1].mi, t[x].mipos = t[x<<1].mipos;else t[x].mi = t[x<<1|1].mi, t[x].mipos = t[x<<1|1].mipos;t[x].cnt1 = t[x<<1].cnt1 + t[x<<1|1].cnt1;t[x].cnt2 = t[x<<1].cnt2 + t[x<<1|1].cnt2; }int query_cnt(int x, int l, int r, int ql, int qr, int type){if(l > r)return 0;if(ql <= l && r <= qr) return type ? t[x].cnt1 : t[x].cnt2;int mid = (l+r)>>1, ret = 0;if(ql <= mid) ret += query_cnt(x<<1,l,mid,ql,qr,type);if(mid < qr) ret += query_cnt(x<<1|1, mid+1,r,ql,qr,type);return ret;}int query_mi(int x, int l, int r, int ql, int qr){if(ql <= l && r <= qr) return t[x].mipos;int mid = (l+r)>>1, p1 = 0, p2 = 0;if(ql <= mid) p1 = query_mi(x<<1,l,mid,ql,qr);if(mid < qr) p2 = query_mi(x<<1|1,mid+1,r,ql,qr);if(!p1 || !p2) return p1?p1:p2;else if(height[p1] < height[p2]) return p1;else return p2;}void SA(){int *x = t1, *y = t2, m = 30;for(int i = 1; i <= n; i++) sum[x[i] = s[i]]++;for(int i = 1; i <= m; i++) sum[i] += sum[i-1];for(int i = n; i >= 1; i--) sa[sum[x[i]]--] = i;for(int k = 1; k <= n; k <<= 1){int p = 0;for(int i = n-k+1; i <= n; i++) y[++p] = i;for(int i = 1; i <= n; i++) if(sa[i] - k > 0) y[++p] = sa[i] - k;for(int i = 1; i <= m; i++) sum[i] = 0;for(int i = 1; i <= n; i++) sum[x[i]]++;for(int i = 1; i <= m; i++) sum[i] += sum[i-1];for(int i = n; i >= 1; i--) sa[sum[x[y[i]]]--] = y[i];swap(x, y);for(int i = 1; i <= n; i++) x[sa[i]] = x[sa[i-1]] + ((y[sa[i]] == y[sa[i-1]] && y[sa[i]+k] == y[sa[i-1]+k]) ? 0 : 1); m = x[sa[n]];if(m >= n) break; // 有力的優(yōu)化 }for(int i = 1; i <= n; i++) rank[sa[i]]= i;for(int k = 0, i = 1; i <= n; height[rank[i++]] = (k?k--:k))for(; s[i+k] == s[sa[rank[i]-1]+k]; k++);}void main(){scanf("%s%s",s1+1,s2+1);n1 = strlen(s1+1); n2 = strlen(s2+1);for(int i = 1; i <= n1; i++) s[++n] = s1[i] - 'a' + 1;s[++n] = 28;for(int i = 1; i <= n2; i++) s[++n] = s2[i] - 'a' + 1;SA(); build(1,1,n);q[0] = (item){1,n};for(int head = 0, tail = 1; head < tail; head++){int l = q[head].l, r = q[head].r;int minpos = query_mi(1,1,n,l+1,r);if(l < minpos-1)q[tail++] = (item){l, minpos-1};if(minpos < r)q[tail++] = (item){minpos, r};ans += (ll) query_cnt(1,1,n,l,minpos-1, 1) * query_cnt(1,1,n,minpos, r, 0) * height[minpos];ans += (ll) query_cnt(1,1,n,l,minpos-1, 0) * query_cnt(1,1,n,minpos, r, 1) * height[minpos];}printf("%lld\n",ans);} } int main() {runzhe2000::main(); } 

總結(jié)

以上是生活随笔為你收集整理的BZOJ 4566 [Haoi2016]找相同字符的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。