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;
}


原文地址:https://www.cnblogs.com/gcczhongduan/p/5180995.html