hihocoder-1407 后缀数组二·重复旋律2 不重合 最少重复K次

 后缀数组不能直接通过Height得出不重合的公共串。我们可以二分k值,这样连续的Height只要都大于等于k,那他们互相间的k值都大于等于k。每个这样的连续区间查找SA的最大最小值,做差判断是否重合(考虑common prefix=k)。

#include <iostream>
#include <cstring>
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <iomanip>
#include <stdlib.h> 
#include <time.h>  
#define LL long long
using namespace std;
const LL mod = 100001;
const LL N = 100010;
class SF
{
    //N:数组大小
public:
    int x[N], y[N], c[N];
    int Height[N],str[N], SA[N], Rank[N];//Height数组从2开始
    int slen;
    int m=1050;//字符集处理大小(传入如果不是数字,需要做位移转换)
    bool cmp(int* r, int a, int b, int l) {
        return r[a] == r[b] && r[a + l] == r[b + l];
    }

    void Suffix(int n) {
        ++n;
        int i, j, p;
        for (i = 0; i < m; ++i) c[i] = 0;
        for (i = 0; i < n; ++i) c[x[i] = str[i]]++;
        for (i = 1; i < m; ++i) c[i] += c[i - 1];
        for (i = n - 1; i >= 0; --i) SA[--c[x[i]]] = i;
        for (j = 1; j <= n; j <<= 1) {
            p = 0;
            for (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 < m; ++i) c[i] = 0;
            for (i = 0; i < n; ++i) c[x[y[i]]]++;

            for (i = 1; i < m; ++i) c[i] += c[i - 1];
            for (i = n - 1; i >= 0; --i) SA[--c[x[y[i]]]] = y[i];

            swap(x, y);
            p = 1; x[SA[0]] = 0;
            for (i = 1; i < n; ++i) {
                x[SA[i]] = cmp(y, SA[i - 1], SA[i], j) ? p - 1 : p++;
            }
            if (p >= n)break;
            m = p;
        }

        int k = 0;
        n--;
        for (i = 0; i <= n; ++i) Rank[SA[i]] = i;
        for (i = 0; i < n; ++i) {
            if (k)--k;
            j = SA[Rank[i] - 1];
            while (str[i + k] == str[j + k])++k;
            Height[Rank[i]] = k;
            //cout << k << endl;
        }
    }
    void init(vector<int> &vv)
    {
        slen = vv.size();
        for (int i = 0; i < slen; i++)
            str[i] = vv[i]+2;//如果是字符,映射成从1开始的序列
        str[slen] = 1;//0作为结束符,防止越界
        Suffix(slen);
    }
    struct nod
    {
        int mx, mi;
    };
    int ans;
    bool ok(int k)
    {
        int temp = 0;
        int mx = 0, mi = 10000;
        bool f = false;
        for (int i = 2; i <= slen; i++)
        {
            if (Height[i] >= k)
            {
                mx = max(mx, max(SA[i - 1], SA[i]));
                mi = min(mi, min(SA[i - 1], SA[i]));
            }
            else
            {
                mx = 0;
                    mi = 10000;
            }
            if (mx - mi >= k)f = true;
        }
        return f;
    }
    int go(int l, int r)
    {
        for (; r >= l; r--)
            if (ok(r))return r;
        return 0;
    }
    int bins(int l, int r)
    {
        while (l <= r)
        {
            if(r-l<=3)
                return go(l, r);
            int mid = (l + r) / 2;
            if (ok(mid))
                l = mid;
            else r = mid - 1;
        }
    }
    LL solve()
    {
        ans=bins(0, slen);
        return ans;
    }
}sf;
LL dp[35][2];
LL n;
int main() {
    cin.sync_with_stdio(false);
    while (cin >> n)
    {
        vector<int> v;
        for (int i = 0; i < n; i++)
        {
            int num;
            cin >> num;
            v.push_back(num);
        }
        sf.init(v);
        cout << sf.solve() << endl;
    }
    return 0;
}

 

posted @ 2017-09-19 18:33  Luke_Ye  阅读(227)  评论(0编辑  收藏  举报