A + B Problem 【LibreOJ - 6158】【exkmp/後綴數組DC3】

題目鏈接


  本題我們可以考慮成從後往前的匹配,因爲要讓後綴最多的爲0,不妨就是從後往前按照需求的進行匹配即可,這個很好想,就是細節有點多了。

  先是講講後綴數組的做法,這裏不能用倍增的後綴數組,因爲還要帶一個log,這樣要是寫的不好可就TLE了,所以這裏用線性複雜度的DC3來寫這道題,然後求出height,找到需求串的位置。然後按照sa函數的排名從前往後和從後往前的分別去考慮,進行相同前綴的計算,然後算出對應的前綴的長度和最多允許的長度,然後再看看如果一邊是滿了的時候,可不可以9或者0的進位(如果前面沒有進位的時候,就是找0)。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 6e6 + 10;
struct DC3
{
    static const int maxn = 6e6 + 10;
#define F(x) ((x)/3+((x)%3==1?0:tb))
#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
    int sa[maxN], rk[maxN], height[maxN], s[maxN];
    int wa[maxn], wb[maxn], wv[maxn], wss[maxn];
    inline int c0(int *r, int a, int b) { return r[a]==r[b] && r[a+1]==r[b+1] && r[a+2]==r[b+2]; }
    inline int c12(int k, int *r, int a, int b)
    {
        if(k==2)
            return r[a]<r[b] || (r[a]==r[b] && c12(1,r,a+1,b+1));
        else return r[a]<r[b] || (r[a]==r[b] && wv[a+1] < wv[b+1]);
    }
    inline void ssort(int *r, int *a, int *b, int n, int m)
    {
        int i;
        for(i=0; i<n; i++) wv[i] = r[a[i]];
        for(i=0; i<m; i++) wss[i] = 0;
        for(i=0; i<n; i++) wss[wv[i]]++;
        for(i=1; i<m; i++) wss[i] += wss[i-1];
        for(i=n-1; i>=0; i--)
            b[--wss[wv[i]]] = a[i];
    }
    inline void dc3(int *r, int *sa, int n, int m)
    {
        int i, j, *rn = r + n;
        int *san = sa + n, ta = 0, tb = (n + 1) / 3, tbc = 0, p;
        r[n] = r[n + 1] = 0;
        for(i=0;i<n;i++) if(i % 3 != 0) wa[tbc++] = i;
        ssort(r+2, wa, wb, tbc, m);
        ssort(r+1, wb, wa, tbc, m);
        ssort(r, wa, wb, tbc, m);
        for(p=1, rn[F(wb[0])] = 0, i = 1; i < tbc; i++)
            rn[F(wb[i])] = c0(r, wb[i-1], wb[i]) ? p - 1 : p++;
        if(p < tbc) dc3(rn, san, tbc, p);
        else for(i=0; i<tbc; i++) san[rn[i]] = i;
        for(i=0; i<tbc; i++) if(san[i]<tb) wb[ta++] = san[i] * 3;
        if(n % 3 == 1) wb[ta++] = n - 1;
        ssort(r, wb, wa, ta, m);
        for(i=0; i<tbc; i++) wv[wb[i]=G(san[i])]=i;
        for(i=0, j=0, p=0; i<ta && j<tbc; p++)
            sa[p]=c12(wb[j]%3, r, wa[i], wb[j]) ? wa[i++] : wb[j++];
        for(; i<ta; p++) sa[p] = wa[i++];
        for(; j<tbc; p++) sa[p] = wb[j++];
    }
    inline void da(int n,int m)
    {
        for(int i=n; i<n*3; i++) s[i]=0;
        dc3(s, sa, n+1, m);
        int i, j, k=0;
        for(i=0;i<=n;i++) rk[sa[i]]=i;
        for(i=0;i<n;i++){
            if(k)k--;
            j=sa[rk[i]-1];
            while(s[i+k] == s[j+k])k++;
            height[rk[i]]=k;
        }
    }
} sa;
char s[maxN];
int N, a[maxN], b[maxN], ans, num0[maxN], num9[maxN];
bool zp[maxN];
int main()
{
    while(scanf("%s", s + 1) != EOF)
    {
        int len = (int)strlen(s + 1);
        for(int i=1; i<=len; i++) a[i] = s[len - i + 1] - '0';
        num0[len + 1] = num9[len + 1] = 0;
        for(int i=len; i>=1; i--)
        {
            if(a[i] == 0) num0[i] = num0[i + 1] + 1;
            else num0[i] = 0;
            if(a[i] == 9) num9[i] = num9[i + 1] + 1;
            else num9[i] = 0;
        }
        bool zero = true;
        b[1] = 10 - a[1];
        if(b[1] == 10) b[1] = 0;
        else zero = false;
        zp[1] = zero;
        for(int i=2; i<=len; i++)
        {
            if(zero)
            {
                b[i] = 10 - a[i];
                if(b[i] == 10) b[i] = 0;
                else zero = false;
            }
            else b[i] = 9 - a[i];
            zp[i] = zero;
        }
        sa.s[0] = 12;
        for(int i=1; i<=len; i++)
        {
            sa.s[i] = a[i] + 1;
        }
        for(int i=1; i<=len; i++)
        {
            sa.s[len + i] = b[i] + 1;
        }
        N = len << 1;
        sa.s[N + 1] = 12;
        sa.s[N + 2] = 12;
        sa.da(N + 2, 15);
//        for(int i=1; i<=N; i++) printf("%d%c", sa.sa[i], i == N ? '\n' : ' ');
//        for(int i=1; i<=N; i++) printf("%d%c", sa.rk[i], i == N ? '\n' : ' ');
//        for(int i=1; i<=N; i++) printf("%d%c", sa.height[i], i == N ? '\n' : ' ');
        int mid_rk = sa.rk[len + 1];
        ans = 0;
        for(int i=mid_rk + 1, H = INF, id, id_pre, id_suff, len_pre, len_suff, tmp; i <= N; i++)
        {
            H = min(H, sa.height[i]);
            if(!H) break;
            id = sa.sa[i];
            if(id > len) continue;
            id_pre = H;
            id_suff = id;
            len_suff = len - id + 1;
            len_pre = len - len_suff;
            tmp = min(H, min(len_pre, len_suff));
            if(tmp == min(len_pre, len_suff))
            {
                if(len_pre > len_suff)
                {
                    if(zp[len_suff]) tmp += num0[len_suff + 1];
                    else tmp += min(num9[len_suff + 1], id - tmp - 1);
                }
                else if(len_suff > len_pre)
                {
                    if(zp[len_pre]) tmp += num0[len_pre + len_pre + 1];
                    else tmp += num9[len_pre + len_pre + 1];
                }
            }
            ans = max(ans, tmp);
        }
        for(int i=mid_rk - 1, H = sa.height[mid_rk], id, id_pre, id_suff, len_pre, len_suff, tmp; i >= 1; i--)
        {
            id = sa.sa[i];
            if(id > len) continue;
            id_pre = H;
            id_suff = id;
            len_suff = len - id + 1;
            len_pre = len - len_suff;
            tmp = min(H, min(len_pre, len_suff));
            if(tmp == min(len_pre, len_suff))
            {
                if(len_pre > len_suff)
                {
                    if(zp[len_suff]) tmp += num0[len_suff + 1];
                    else tmp += min(num9[len_suff + 1], id - tmp - 1);
                }
                else if(len_suff > len_pre)
                {
                    if(zp[len_pre]) tmp += num0[len_pre + len_pre + 1];
                    else tmp += num9[len_pre + len_pre + 1];
                }
            }
            ans = max(ans, tmp);
            H = min(H, sa.height[i]);
            if(!H) break;
        }
        printf("%d\n", ans);
    }
    return 0;
}
/*
2872
ans:2
19919
ans:3
91991
ans:3
9199
ans:1
901
ans:1
9901
ans:2
9911
ans:1
2018
ans:1
109
ans:1
9091
ans:2
12080
ans:2
1000
ans:2
9545455
ans:4
95454545455
ans:6
10090
ans:2
15999841
ans:5
*/

  再講講exkmp的做法,如果使用擴展kmp的話,我們可以先去一樣的處理出本串對於查詢串(也就是需求串的)的最大匹配,也就是每個後綴的最長前綴長度,ex數組。然後與後綴數組相同的來去進行判斷。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define eps 1e-6
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
//const int maxN = 100;
const int maxN = 1e6 + 7;
char A[maxN], B[maxN];
bool Zop[maxN];
int sa[maxN], sb[maxN];
int lena, lenb, num0[maxN], num9[maxN];
int p[maxN], ex[maxN];
//p數組是用來讓B串自己匹配自己的
void exkmp()
{
    p[1] = lenb;
    int x = 1;
    while(sb[x] == sb[x + 1] && x + 1 <= lenb) x++;   //因爲我們p[1]是具有一定性,所以我們不能直接用,所以要先暴力求出p[2]
    p[2] = x - 1;
    int k = 2;
    for(int i=3; i<=lenb; i++)
    {
        int pp = k + p[k] - 1, L = p[i - k + 1];    //pp實際上是p
        if(i + L < pp + 1) p[i] = L;//i-k+L<pp-k+1化簡後i+L<pp
        else
        {
            int j = pp - i + 1;
            if(j < 0) j = 0;
            while(sb[j + 1] == sb[i + j] && i + j <= lenb) j++;
            p[i] = j;
            k = i;
        }
    }
    x = 1;
    while(sa[x] == sb[x] && x <= lenb) x++;//ex[1]並不具有一定性,所以我們暴力求出ex[1]
    ex[1] = x - 1;
    k = 1;
    for(int i=2; i<=lena; i++)
    {
        int pp = k + ex[k] - 1, L = p[i - k + 1];
        if(i + L < pp + 1) ex[i] = L;
        else
        {
            int j = pp - i + 1;
            if(j < 0) j = 0;
            while(sb[j + 1] == sa[i + j] && i + j <= lena && j <= lenb) j++;
            ex[i] = j;
            k = i;
        }
    }
}
int main()
{
    while(scanf("%s", A + 1) != EOF)
    {
        lena = (int)strlen(A + 1); lenb = lena;
        for(int i=1; i<=lena; i++)
        {
            sa[i] = A[lena + 1 - i] - '0';
        }
        for(int i=lena, pos0 = lena, pos9 = lenb; i>=1; i--)
        {
            if(sa[i] == 0)
            {
                pos9 = i - 1;
            }
            else if(sa[i] == 9)
            {
                pos0 = i - 1;
            }
            else { pos0 = pos9 = i - 1; }
            num0[i] = pos0 - i + 1;
            num9[i] = pos9 - i + 1;
        }
        bool zero = true;
        sb[1] = 10 - sa[1];
        if(sb[1] == 10) sb[1] = 0;
        else zero = false;
        for(int i=2; i<=lenb; i++)
        {
            if(zero)
            {
                sb[i] = 10 - sa[i];
                if(sb[i] == 10) sb[i] = 0;
                else zero = false;
            }
            else
            {
                sb[i] = 9 - sa[i];
            }
            Zop[i] = zero;
        }
        exkmp();
//        printf("bp: "); for(int i=1; i<=lenb; i++) printf("%d%c", p[i], i == lenb ? '\n' : ' ');
//        printf("ex: "); for(int i=1; i<=lena; i++) printf("%d%c", ex[i], i == lena ? '\n' : ' ');
        int ans = 0;
        for(int i=2, len_pre, len_suff; i<=lena; i++)
        {
            len_pre = ex[i];
            len_pre = min(len_pre, i - 1);
            len_suff = lena - i + 1;
            if(len_pre < i - 1)
            {
                if(len_pre >= len_suff)
                {
                    ans = max(ans, len_pre + min(num9[len_pre + 1], i - 1 - len_pre));
                }
                else
                {
                    ans = max(ans, len_pre);
                }
            }
            else
            {
                if(i + len_pre == lena + 1) ans = max(ans, len_pre);
                else if(Zop[i + len_pre - 1])
                {
                    ans = max(ans, len_pre + num0[i + len_pre]);
                }
                else
                {
                    ans = max(ans, len_pre + num9[i + len_pre]);
                }
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}
/*
15999841
ans:5
9901
ans:2
95454545455
ans:6
*/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章