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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

HDU5853 Jong Hyok and String(二分 + 后缀数组)

發布時間:2024/1/17 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HDU5853 Jong Hyok and String(二分 + 后缀数组) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目

Source

http://acm.hdu.edu.cn/showproblem.php?pid=5853

Description

Jong Hyok loves strings. One day he gives a problem to his friend you. He writes down n strings Pi in front of you, and asks m questions. For i-th question, there is a string Qi. We called strange set(s) = {(i, j) | s occurs in Pi and j is the position of its last character in the current occurence}. And for ith question, you must answer the number of different strings t which satisfies strange set(Qi) = strange set(t) and t is a substring of at least one of the given n strings.

Input

First line contains T, a number of test cases.

For each test cases, there two numbers n, m and then there are n strings Pi and m strings Qj.(i = 1…n, j = 1…m)


1 <= T <= 10
1 <= n <= 100000
1 <= m<= 500000
1 <=|Pi|<=100000
1 <=|Qi|<=100000
∑ni=1|Pi|≤100000
File size is less than 3.5 megabytes.

Output

For each test case, first line contains a line “Case #x:”, x is the number of the case.

For each question, you should print one integer in one line.

Sample Input

1
2 2
aba
ab
a
ab

Sample Output

Case #1:
1
2

?

分析

題目大概說給若干的字符串pi,然后若干個詢問,詢問pi內有多少個不同子串與給定的詢問字符串的strange set相同。一個字符串的strange set是一個二元組(i,j)的集合,表示該字符串在pi中出現且最后一個字符在pi中的位置j。

?

這題比賽時和隊友討論了挺久的。

首先想到的是,與查詢串的strange set相同一定是查詢串的后綴(其實不止是這樣= =)。而查詢串后綴的strange set不與查詢串相同的情況是這個后綴在pi中被匹配了,但在那個位置查詢串沒被匹配。

然后隊友考慮到通過把串反轉,將后綴轉化成前綴。

接下去,看到Σ|pi|<=100000,所以開始往后綴數組上面想。自然,那些pi要反轉(這時考慮的是前綴了),然后拼接起來,中間用特殊字符隔開。

而求得其各個后綴排序后,對于任何一個模式串是能通過二分去查找到它所在匹配位置。然后就開始考慮對于查詢串的各個前綴,去通過二分其位置的上下界求得有多少個與其匹配,然后再與查詢串匹配次數對比,如果相等說明該前綴是可行的。

不過時間復雜度顯然不行。后面我想到如果前綴x不行,那么前綴x-1也一定不行,然后慢慢地得出了這個結論——

  • 對于各個查詢串,通過兩次二分,找到它匹配的上界upp和下界low(upp<=low。。),那么結果就是|查詢串|-max(LCP(upp,upp-1),LCP(low,low+1))!

我們驗證了時間復雜度,是所有查詢串總長*logΣ|pi|,所有查詢串總長Clarification說到200W左右,那樣大概是可以一試的。于是就寫了,不過WA= =二分改了改,然后什么什么。。比賽結束也沒搞出來。

?

其實,一開始邏輯就有漏洞了。。【與查詢串的strange set相同一定是查詢串的后綴(其實不止是這樣= =)】,還有一種情況!

比如這個數據:

1?1
bbbaa
bba? 結果應該是3,因為:
  • strange?set(“bba”) = {(1,4)}
  • bba的這兩個后綴滿足:strange?set(“bba”) = {(1,4)}、strange?set(“ba”) = {(1,4)}
  • 此外還有這個滿足:strange?set(“bbba”) = {(1,4)}
就是說還有包含整個字符串的可能滿足。然后我想了想,畫了畫,又得出結論:
  • 這種情況的數量就是上下界的LCP長度減去查詢串的長度!
另外要注意上界=下界的情況,還有特殊字符在這兒應該要互不相同。。 感覺這題好難描述= =就這樣吧。。最后我終于AC了。。

代碼

#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define INF (1<<30) #define MAXN 222222int wa[MAXN],wb[MAXN],wv[MAXN],ws[MAXN]; int cmp(int *r,int a,int b,int l){return r[a]==r[b] && r[a+l]==r[b+l]; } int sa[MAXN],rnk[MAXN],height[MAXN]; void SA(int *r,int n,int m){int *x=wa,*y=wb;for(int i=0; i<m; ++i) ws[i]=0;for(int i=0; i<n; ++i) ++ws[x[i]=r[i]];for(int i=1; i<m; ++i) ws[i]+=ws[i-1];for(int i=n-1; i>=0; --i) sa[--ws[x[i]]]=i;int p=1;for(int j=1; p<n; j<<=1,m=p){p=0;for(int i=n-j; i<n; ++i) y[p++]=i;for(int i=0; i<n; ++i) if(sa[i]>=j) y[p++]=sa[i]-j;for(int i=0; i<n; ++i) wv[i]=x[y[i]];for(int i=0; i<m; ++i) ws[i]=0;for(int i=0; i<n; ++i) ++ws[wv[i]];for(int i=1; i<m; ++i) ws[i]+=ws[i-1];for(int i=n-1; i>=0; --i) sa[--ws[wv[i]]]=y[i];swap(x,y); x[sa[0]]=0; p=1;for(int i=1; i<n; ++i) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;}for(int i=1; i<n; ++i) rnk[sa[i]]=i;int k=0;for(int i=0; i<n-1; height[rnk[i++]]=k){if(k) --k;for(int j=sa[rnk[i]-1]; r[i+k]==r[j+k]; ++k);} }int st[18][MAXN]; void ST(int *a,int n){for(int i=1; i<=n; ++i) st[0][i]=a[i];for(int i=1; i<18; ++i){for(int j=1; j<=n; ++j){if(j+(1<<i)>n) break;st[i][j]=min(st[i-1][j],st[i-1][j+(1<<i-1)]);}} } int rmq(int a,int b){if(a>b) swap(a,b);int k=(int)(log2(b-a+1)+1e-6);return min(st[k][a],st[k][b-(1<<k)+1]); }char str[MAXN]; int an,a[MAXN],b[MAXN],bn; int len[MAXN];int cmp(int k){int i;for(i=0; i+k<an && i<bn; ++i){if(a[i+k]>b[i]) return 1;else if(a[i+k]<b[i]) return -1;}if(i!=bn) return -1;return 0; }int main(){int t,n,m;scanf("%d",&t);for(int cse=1; cse<=t; ++cse){scanf("%d%d",&n,&m);an=0;for(int i=0; i<n; ++i){scanf("%s",str);for(int j=strlen(str)-1; j>=0; --j){len[an]=j+1;a[an++]=str[j]-'a'+1;}a[an++]=28+i;}a[an++]=0;SA(a,an,28+n);ST(height,an-1);printf("Case #%d:\n",cse);while(m--){scanf("%s",str);bn=0;for(int j=strlen(str)-1; j>=0; --j){b[bn++]=str[j]-'a'+1;}int l=1,r=an-1;int upp=-1;while(l<=r){int mid=l+r>>1;int tmp=cmp(sa[mid]);if(tmp==0){upp=mid;r=mid-1;}else if(tmp>0) r=mid-1;else if(tmp<0) l=mid+1;}if(upp==-1){printf("%d\n",0);continue;}l=1,r=an-1;int low=-1;while(l<=r){int mid=l+r>>1;int tmp=cmp(sa[mid]);if(tmp==0){low=mid;l=mid+1;}else if(tmp>0) r=mid-1;else if(tmp<0) l=mid+1;}int tmp=0;if(upp!=1){tmp=max(tmp,height[upp]);}if(low!=an-1){tmp=max(tmp,height[low+1]);}if(upp==low) printf("%d\n",bn-tmp+len[sa[upp]]-bn);else printf("%d\n",bn-tmp+rmq(upp+1,low)-bn);}}return 0; }

?

轉載于:https://www.cnblogs.com/WABoss/p/5778329.html

總結

以上是生活随笔為你收集整理的HDU5853 Jong Hyok and String(二分 + 后缀数组)的全部內容,希望文章能夠幫你解決所遇到的問題。

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