zoukankan      html  css  js  c++  java
  • CSU1608: Particle Collider(后缀数组)

    Description

    In the deep universe, there is a beautiful planet named as CS on which scientists have decided to build Immense Colossal Particle Collider (i.e. ICPC) to find the ultimate theory of the universe. The ICPC is made up with several fragments, and each fragment has a series of energy level. Any continuous sub-series of energy level corresponds to one type of microscopic particle and can accelerate it with a remarkable effect. Scientists have found that the observation of the certain type of particle is remarkable enough if its corresponding energy level sub-series appears in more than one half fragments. Another thing, the reverse of one specific sub-series of energy level corresponds to the antiparticle of the particle corresponded by its original sub-series. As we all know, when a particle meets its antiparticle, DUANG DUANG, a very remarkable phenomenon can be observed by scientists. For simplicity, scientists have declared that it is not remarkable enough until the total count of the appearance in the different fragments of the original sub-series and its reverse is more than one half the number of fragments. Lastly, both in the first and the second condition, the longer the sub-series is, the more remarkable observation can be get.
    Well, so long a paragraph, science is really complicated. Now, questions come: given a set of fragments with a series of energy level, find the sub-series which can get the most remarkable observation.

    Input

    There are several cases. Every case comes a line with a positive integer N (N <= 10) first of all, followed by N lines each of which contains a nonempty series of capital letters representing energy levels. All series have a length not more than 1000.

    Output

    For every case, output the wanted sub-series. If there are more than one, output them in the alphabetical order, each in one line. If there is none, output NONE. Note that whenever one sub-series and its reverse appear simultaneously with the satisfied condition, it is available to output only the less one in alphabetical order of them two even if any of them two appears more than one half N times.

    Sample Input

    3
    ABC
    ABD
    BCD
    3
    AAA
    BBB
    CCC
    2
    ABC
    DBA

    Sample Output

    AB
    BC
    NONE
    AB

    HINT

    Source



    题意:
    要求全部正向或者反向出如今超过k/2个串中的子串

    思路:
    还是和曾经一样二分答案。使用二进制来标记状态

    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <stack>
    #include <queue>
    #include <map>
    #include <set>
    #include <vector>
    #include <math.h>
    #include <bitset>
    #include <algorithm>
    #include <climits>
    using namespace std;
    
    #define LS 2*i
    #define RS 2*i+1
    #define UP(i,x,y) for(i=x;i<=y;i++)
    #define DOWN(i,x,y) for(i=x;i>=y;i--)
    #define MEM(a,x) memset(a,x,sizeof(a))
    #define W(a) while(a)
    #define gcd(a,b) __gcd(a,b)
    #define LL long long
    #define N 1000005
    #define MOD 1000000007
    #define INF 0x3f3f3f3f
    #define EXP 1e-8
    int wa[N],wb[N],wsf[N],wv[N],sa[N];
    int rank1[N],height[N],s[N],a[N];
    //sa:字典序中排第i位的起始位置在str中第sa[i]
    //rank:就是str第i个位置的后缀是在字典序排第几
    //height:字典序排i和i-1的后缀的最长公共前缀
    int cmp(int *r,int a,int b,int k)
    {
        return r[a]==r[b]&&r[a+k]==r[b+k];
    }
    void getsa(int *r,int *sa,int n,int m)//n要包括末尾加入的0
    {
        int i,j,p,*x=wa,*y=wb,*t;
        for(i=0; i<m; i++)  wsf[i]=0;
        for(i=0; i<n; i++)  wsf[x[i]=r[i]]++;
        for(i=1; i<m; i++)  wsf[i]+=wsf[i-1];
        for(i=n-1; i>=0; i--)  sa[--wsf[x[i]]]=i;
        p=1;
        j=1;
        for(; p<n; j*=2,m=p)
        {
            for(p=0,i=n-j; i<n; i++)  y[p++]=i;
            for(i=0; i<n; i++)  if(sa[i]>=j)  y[p++]=sa[i]-j;
            for(i=0; i<n; i++)  wv[i]=x[y[i]];
            for(i=0; i<m; i++)  wsf[i]=0;
            for(i=0; i<n; i++)  wsf[wv[i]]++;
            for(i=1; i<m; i++)  wsf[i]+=wsf[i-1];
            for(i=n-1; i>=0; i--)  sa[--wsf[wv[i]]]=y[i];
            t=x;
            x=y;
            y=t;
            x[sa[0]]=0;
            for(p=1,i=1; i<n; i++)
                x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++;
        }
    }
    void getheight(int *r,int n)//n不保存最后的0
    {
        int i,j,k=0;
        for(i=1; i<=n; i++)  rank1[sa[i]]=i;
        for(i=0; i<n; i++)
        {
            if(k)
                k--;
            else
                k=0;
            j=sa[rank1[i]-1];
            while(r[i+k]==r[j+k])
                k++;
            height[rank1[i]]=k;
        }
    }
    
    char str[N];
    int id[N];
    map<string,int> mat,ans;
    map<string,int>::iterator it;
    
    int check(int x)//统计该状态包括几个串
    {
        int i,cnt = 0;
        for(i = 1; i<=10; i++)
            if((1<<i)&x)
                cnt++;
        return cnt;
    }
    
    int main()
    {
        int n,i,j,k,len;
        while(~scanf("%d",&k))
        {
            MEM(id,0);
            n = 0;
            int p = 200;
            for(i = 1; i<=k; i++)
            {
                scanf("%s",str);
                len = strlen(str);
                for(j = 0; j<len; j++)
                {
                    id[n] = i;
                    s[n++] = str[j];
                }
                s[n++] = p++;
                for(j = len-1; j>=0; j--)
                    s[n++] = str[j];
                s[n++] = p++;
            }
            if(k == 1)
            {
                printf("%s
    ",str);
                continue;
            }
            getsa(s,sa,n,p);
            getheight(s,n);
            int l = 1,r = 1000;
            ans.clear();
            while(l<=r)
            {
                int mid = (l+r)/2;
                i = 0;
                mat.clear();
                while(i<n)
                {
                    if(height[i]>=mid)
                    {
                        int tem = 1<<id[sa[i-1]];
                        len = 2000;
                        while(height[i]>=mid && i<n)//二进制记录串
                        {
                            tem |= (1<<id[sa[i]]);
                            len = min(len,height[i]);
                            i++;
                        }
                        if(tem!=1)
                        {
                            char s1[1005],s2[1005];
                            for(j = len-1; j>=0; j--)
                            {
                                s1[len-1-j] = s[sa[i-1]+j];
                                s2[j] = s[sa[i-1]+j];
                            }
                            s1[len] = s2[len] = '';
                            if(mat.find(string(s1)) != mat.end())
                                mat[string(s1)] |= tem;
                            else
                                mat[string(s2)] = tem;
                        }
                    }
                    i++;
                }
                int flag = 0;
                for(it = mat.begin(); it!=mat.end(); it++)
                {
                    if(check(it->second) >= k/2+1)
                    {
                        if(flag==0)
                        {
                            ans.clear();
                            flag = 1;
                        }
                        ans.insert(*it);
                    }
                }
                if(flag==0) r = mid-1;
                else l = mid+1;
            }
            if(ans.size()==0)
                printf("NONE
    ");
            else
            {
                for(it = ans.begin(); it!=ans.end(); it++)
                {
                    printf("%s
    ",it->first.c_str());
                }
            }
        }
    
        return 0;
    }
    


  • 相关阅读:
    Studio更新
    gradle 两种更新方法
    Handler基本用法
    使用git克隆指定分支的代码
    Bugly最简单的配置方法
    setTag,getTage复用
    Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2
    Android应用如何跳转到应用市场详情页面
    bzoj千题计划249:bzoj5100: [POI2018]Plan metra
    bzoj千题计划248:bzoj3697: 采药人的路径
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/5180995.html
Copyright © 2011-2022 走看看