J - Life Forms POJ - 3294

后缀数组加上二分。(其实单调栈也行,二分也是因为其单调性)
首先,我们如果利用two pointers的思想来看,从lf出发,rt不断往前面跳转,公共子串长度为min lcp(lf,rt),当且仅当lf到rt之间,字串出现在了n/2个主串时候停止。
那么这个时候如果rt再往下走,依然满足题意,但同时,因为求的是最长字串,我们往下走取得是min(lcp(lf,rt))所以对于答案来说,不会有正向收益。
这就是我们二分的来源。我们以次二分,枚举最长公共子串的长度len,暴力判断是否满足题意,因为我们二分的长度,所以就不用考虑min lcp带来的影响,只用考虑是否满足n/2,所以我们这里贪心的匹配,尽力做到满足即可。
对于长度一定,可能有多个字符串的时候,在同一个分区里面,结果是一样的,不同分区里面,单独计算即可。(后缀数组已经按照字典序排列)
坑点:不能用#分割字符串,因为有至多100个字符串,那么就可能会有#这个字符串被匹配进来。应该开int数组来解决。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<bitset>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
typedef unsigned long long ull;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int inf = 1e9;
using namespace std;
ll read()
{
    char ch = getchar(); ll x = 0, f = 1;
    while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}
typedef pair<int, int> pir;
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lrt root<<1
#define rrt root<<1|1
const int N = 2e5 + 10;
int rk[N], height[N], sa[N], t[N], t2[N], c[N];
int s[N];
string ts;
int n;
int T;
int limited;
int index[N];
int vis[105];
int ans[N];
void da() {
    int *x = t;
    int *y = t2;
    int m = 330;
    up(i, 0, m)c[i] = 0;
    up(i, 0, n)c[x[i] = s[i]]++;
    up(i, 1, m)c[i] += c[i - 1];
    dwd(i, n - 1, 0)sa[--c[x[i]]] = i;
    for (int k = 1; k <= n; k <<= 1)
    {
        int p = 0;
        up(i, n - k, n)y[p++] = i;
        up(i, 0, n)if (sa[i] >= k)y[p++] = sa[i] - k;
        up(i, 0, m)c[i] = 0;
        up(i, 0, n)c[x[y[i]]]++;
        up(i, 1, m)c[i] += c[i - 1];
        dwd(i, n - 1, 0)sa[--c[x[y[i]]]] = y[i];
        swap(x, y);
        p = 1;
        x[sa[0]] = 0;
        up(i, 1, n)
            x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1 : p++;
        if (p >= n)break;
        m = p;
    }
}
void getheight() {
    up(i, 0, n)
        rk[sa[i]] = i;
    int j = 0;
    int k = 0;
    up(i, 0, n)
    {
        if (k)k--;
        j = sa[rk[i] - 1];
        while (s[i + k] == s[j + k])k++;
        height[rk[i]] = k;
    }
}
void test()
{
    cout << "suffix:" << endl;
    up(i, 0, n)
    {
        //cout << "sa" << sa[i] << endl;
        up(j, sa[i], n)cout << s[j] << " ";
        cout << endl;
        cout << height[i] << endl;
    }
}
bool judge(int len)
{
    memset(vis, 0, sizeof(vis));
    int num = 0;
    int now = 0;
    up(i, 1, n)
    {
        if (height[i] >= len && s[sa[i]] != '#')
        {
            num += vis[index[sa[i]]] ? 0 : 1;
            vis[index[sa[i]]] = 1;
            num += vis[index[sa[i - 1]]] ? 0 : 1;
            vis[index[sa[i - 1]]] = 1;
        }
        else
        {
            if (num > limited)ans[now++] = sa[i - 1];
            memset(vis, 0, sizeof(vis));
            num = 0;
        }
    }
    if (num > limited)ans[now++] = sa[n - 1];
    if (now)
    {
        ans[now] = -1;
        return 1;
    }
    else { return 0; }
}
void work()
{
    int lf = -1, rt = n;
    memset(ans, -1, sizeof(ans));
    while (rt > lf + 1)
    {
        int mid = (lf + rt) / 2;
        if (judge(mid))lf = mid;
        else rt = mid;
    }
    if (lf == 0)cout << "?" << endl;
    else {
        for (int i = 0; ans[i] != -1; i++)
        {
            up(j, 0, lf)
            {
                cout << (char)s[ans[i] + j];
            }
            cout << endl;
        }
    }
    cout << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    while (scanf("%d", &T) && T)
    {
        int cnt = 0;
        up(i,0,T)
        {
            cin >> ts;
            for (int j=0;j<ts.size();j++)
            {
                s[cnt] = ts[j];
                index[cnt++] = i;
            }
            s[cnt] = 150 + i;
            index[cnt++] = i;
        }
        s[cnt] = 30;
        index[cnt++] = T;
    //  cout << s;
        n = cnt;
        da();
        //test();
        getheight();
        limited = T / 2;
        work();
    }
}

猜你喜欢

转载自www.cnblogs.com/LORDXX/p/11992410.html