• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            算法學(xué)社
            記錄難忘的征途
            posts - 141,comments - 220,trackbacks - 0

            題目描述:

                給N個串(N<100,000),總長不超過100,000。對于每個串,求至少在其他k個串中作為子串出現(xiàn)過的子串個數(shù)。

            算法分析:

                
                不難想到在若干個串中,找滿足****性質(zhì)的子串,可以用后綴數(shù)組求LCP解決。
                這里有一個性質(zhì),就是如果對于串S的后綴串Si,子串Sij滿足題目的性質(zhì),那么Sii...Sij都會滿足。
                這樣解的分部具有單調(diào)性,二分答案來求解。
                對于串LCPij,我們要找到含有LCPij的所有后綴串。用線段樹不難找到。
                設(shè)LCP(p...q)都含有Sij。下面我們的問題是,LCP(p...q)對應(yīng)多少個原串。
                一開始我也蒙了,后來才知道根本不用求出對應(yīng)多少個原串,只需知道是否大于等于k就可以了。
                我們掃一遍,預(yù)處理出LCP數(shù)組中對于r,最大的滿足LCP(l,r)對應(yīng)k個原串的l。
                這題非常爽!! 又AK了一場,更爽!!!
            #include<iostream>
            #include<algorithm>
            #include<cstdio>
            #include<cassert>
            #include<cstring>
            using namespace std;
            typedef unsigned long long ull;
            const int BS = 37;
            const int N = 2* int(1e5) + 10;
            char ch[N];
            ull hash[N], base[N], ans[N];
            int sa[N], lcp[N], pos[N] , n , k, P[N];
            int seg[N<<2], M, len;
            // suffix array
            inline int cal(int a,int b,int c){
                if( a > b) swap(a,b);
                int l = 0;
                int r; if(c==0) r = len-b;
                else r = min(pos[P[a]+1]-a-1,pos[P[b]+1]-b-1);
                while(l<r){
                    int mid = l+r >>1;
                    if( hash[a] - hash[a + mid + 1] == (hash[b] - hash[b + mid + 1]) * base[b-a]) l = mid + 1; else r = mid;
                }
                return r;
            }
            bool cmp(int a,int b) {
                int l = cal(a,b,0);
                if(a + l == len) return 1;
                if(b + l == len) return 0;
                assert(ch[a+l] != ch[b+l]);
                return ch[a+l] < ch[b+l];
            }
            // queue
            int flag[N],R[N],pa[N];
            void init(){
                for(int i=0;i<len;i++){
                    pa[i] = P[sa[i]];
                    flag[i] = -1;
                }
                int cnt = 0,now = 0;
                for(int i=0;i<len;i++){
                    if(flag[pa[i]] == -1){
                        cnt ++;
                    }
                    flag[pa[i]] = i;
                    if(cnt<k) R[i] = now;
                    else if(cnt == k){
                        while(flag[pa[now]]!= now) now++;
                        R[i] = now;
                    }
                    else {
                        flag[pa[now]] = -1;
                        now ++;
                        while(flag[pa[now]]!= now) now++;
                        R[i] = now;
                        cnt --;
                    }
                }
            }
            // segment tree
            int dfs(int p,int c,int v){
                if(p >= M) return p;
                if(c){
                    if(seg[p<<1|1] < v)return dfs(p<<1|1,c,v);
                    else return dfs(p<<1,c,v);
                }
                else {
                    if(seg[p<<1] < v) return dfs(p<<1,c,v);
                    else return dfs(p<<1|1,c,v);
                }
            }
            bool upt(int p,int v){
                if(v == 0) return N;
            //    cout<<"upt: "<<p<<" "<<v<<" ";
                int r = -1, l = -1;
                if(seg[p+=M] < v) r = p;
                for(;p>1;p>>=1){
                    if(p&1) if(l==-1) if(seg[p^1] < v) l = dfs(p^1,1,v);
                    if(~p&1) if(r==-1) if(seg[p^1]< v) r = dfs(p^1,0,v);
                }
            //    cout<<l-M<<" "<<r-M<<endl;
                l-=M, r-=M;
                return R[r] > l;
            }
            // debug
            int OP(int p){while(ch[p]!='$') cout<<ch[p++];}
            // main
            int main(){
                base[0] = 1;
                for(int i=1;i<N;i++) base[i] = base[i-1] * BS;
                while(~scanf("%d%d",&n,&k)){
                    pos[0] = 0;
                    for(int i=0;i<n;i++){
                        scanf("%s",ch + pos[i]);
                        pos[i+1] = pos[i] + strlen(ch + pos[i]) + 1;
                        ch[pos[i+1]-1] = '$';
                    }
                    len = pos[n];
                    int nowp = 0;
                    for(int i=0;i<len;i++) {P[i] = nowp; if(ch[i]=='$') nowp++;}
            //        for(int i=0;i<len;i++) cout<<P[i]<<" "; cout<<endl;
                    
            // build lcp
                    hash[len]  = 0;
                    for(int i=len-1;i>=0; i--)
                        hash[i] = hash[i+1]+ base[len-1-i] * (ch[i] == '$' ? 0 : ch[i] - 'a' + 1);
                    for(int i=0;i<len;i++) sa[i] = i;
                    stable_sort(sa, sa + len, cmp);
                    for(int i=0;i<len-1;i++) lcp[i] = cal(sa[i],sa[i+1],1);
                    lcp[len] = lcp[len-1] = 0;
                    // build seg
                    for(int i=30;i;i--) if((1<<i) > len) M = 1<<i;
                    for(int i=M;i<M+M;i++) seg[i] = ~0u>>2;
                    for(int i=0;i<=len;i++) seg[i+M] = lcp[i];
                    for(int i=M-1;i;i--) seg[i] = min(seg[i<<1] , seg[i<<1|1]);
                    init();
                    memset(ans,0,sizeof(ans));
                    for(int i = n; i < len; i++){
                        int p = P[sa[i]];
                        int l = 0, r = pos[p+1] - sa[i] ;
            //            OP(sa[i]); cout<<" "<<l<<" "<<r<<endl;
                        while(l<r) {
                            int mid = l + r >> 1; 
                            if( upt(i,mid)) l = mid +1;
                            else r = mid;
                        }
            //            OP(sa[i]);cout<<" "<<lcp[i]<<" "<<r-1<<endl;
                        ans[p] += r-1;
                    }
                    for(int i=0;i<n;i++)
                        cout<<ans[i]<<" "; cout<<endl;
                }
            }
            posted on 2012-07-26 10:20 西月弦 閱讀(759) 評論(1)  編輯 收藏 引用 所屬分類: 解題報告

            FeedBack:
            # re: codeforces 204E 后綴數(shù)組+線段樹
            2013-04-10 23:51 | acm愛好者
            你好,不知可否此題在詳述一下?我想此題想了很久了。。一直沒懂怎么寫,能否發(fā)郵件交流?luyuncheng@sina.com  回復(fù)  更多評論
              
            久久高清一级毛片| 99久久婷婷国产综合亚洲| 精品无码久久久久久久动漫| 久久久久久a亚洲欧洲aⅴ| 国产精品综合久久第一页| 青青草原综合久久大伊人| 无码日韩人妻精品久久蜜桃 | 久久久久亚洲精品无码网址| 偷偷做久久久久网站| 国产精品久久久久久吹潮| 久久精品夜色噜噜亚洲A∨| 亚洲AV无码1区2区久久| 91精品免费久久久久久久久| 久久亚洲中文字幕精品一区| 日本精品久久久久中文字幕8| 久久伊人五月天论坛| 一本色道久久HEZYO无码| 久久精品国产精品亚洲艾草网美妙| 国产69精品久久久久APP下载| 狠狠色丁香久久婷婷综| 久久人人爽人人人人片av| 久久99精品久久久久久野外| 999久久久无码国产精品| 久久久久久精品免费看SSS | 日批日出水久久亚洲精品tv| 99久久99久久精品免费看蜜桃| 亚洲精品无码专区久久同性男| 久久99国产精品一区二区| 人妻精品久久久久中文字幕69| 亚洲精品WWW久久久久久| 国产精品久久久99| 四虎国产永久免费久久| 精品午夜久久福利大片| 精品国产91久久久久久久| 国产精品99久久久精品无码| 国产精品99久久久精品无码 | 久久亚洲精品成人无码网站| 人妻精品久久久久中文字幕| 国产免费久久久久久无码| 国产ww久久久久久久久久| 精品水蜜桃久久久久久久|