SDOI2008 Sandy的卡片

传送门

这题数据范围贼小……听说可以用各种乱七八糟的暴力随便过去。

其实这题就是找最长公共子串。但是我一直不知道怎么处理加数的情况……今天豁然开朗,直接对每个串做一次差分就好了。

之后就是我们正常的匹配,每次用子树内的值更新节点的值,最后的时候答案取所有节点最小匹配值的最大值+1.

#include<bits/stdc++.h>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')

using namespace std;
typedef long long ll;
const int M = 100005;
const int N = 2000005;
const ll INF = 5e18;

int read()
{
   int ans = 0,op = 1;char ch = getchar();
   while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
   while(ch >='0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
   return ans * op;
}

int n,ans,maxn[M],minn[M],a[M],c[M],b[M];

struct Suffix
{
    map <int,int> ch[M];
    int last,cnt,fa[M],l[M];
    void extend(int c)
    {
        int p = last,np = ++cnt;
        l[np] = l[p] + 1,last = cnt;
        while(p && !ch[p].count(c)) ch[p][c] = np,p = fa[p];
        if(!p) {fa[np] = 1;return;}
        int q = ch[p][c];
        if(l[q] == l[p] + 1) fa[np] = q;
        else
        {
            int nq = ++cnt;
            l[nq] = l[p] + 1,ch[nq] = ch[q];
            fa[nq] = fa[q],fa[np] = fa[q] = nq;
            while(ch[p][c] == q) ch[p][c] = nq,p = fa[p];
        }
    }
    void cal()
    {
        rep(i,1,cnt) c[l[i]]++;
        rep(i,1,cnt) c[i] += c[i-1];
        rep(i,1,cnt) a[c[l[i]]--] = i;
    }
    void match(int *b,int k)
    {
        int u = 1,len = 0;
        rep(i,2,k) 
        {
            int f = b[i] - b[i-1];
            while(u != 1 && !ch[u][f]) u = fa[u],len = l[u];
            if(ch[u][f]) len++,u = ch[u][f],maxn[u] = max(maxn[u],len);
        }
        per(i,cnt,1)
        {
            int p = a[i];
            maxn[fa[p]] = max(maxn[fa[p]],min(maxn[p],l[fa[p]]));
            minn[p] = min(minn[p],maxn[p]),maxn[p] = 0;
        }
    }
}SAM;

int main()
{
    n = read(),SAM.cnt = SAM.last = 1;
    memset(minn,0x3f,sizeof(minn));
    int k = read();
    rep(i,1,k) {b[i] = read(); if(i >= 2) SAM.extend(b[i] - b[i-1]);}
    SAM.cal();
    rep(i,2,n)
    {
        int k = read();
        rep(i,1,k) b[i] = read();
        SAM.match(b,k);
    }
    rep(i,1,SAM.cnt) ans = max(ans,minn[i]+1);
    printf("%d\n",ans);
    return 0;
}
posted @ 2019-01-16 06:34  CaptainLi  阅读(104)  评论(0编辑  收藏  举报