列表

详情


NC17495. 后缀自动鸡

描述

后缀自动鸡是一只这样的鸡,它通吃一个串的所有子串,还能知道吃了多少不同的子串。 你今天要挑战的问题是给定一个串,问这个串中所有长度为 k 的子串中,哪个串拥有最多的不同的子串,请输出这个串和它拥有的不同子串的个数,如果有多个符合条件,请输出字典序最小的一个。

输入描述

第一行一个串 s。
第二行一个正整数 q。表示询问个数。
接下来 q 行每行一个数 k(1<=k<=|s|),表示一个询问 k(意义如上)。其中|s|表示 s 的长度。

输出描述

每行依次为字典序最小的拥有最多的不同的子串、一个空格、符合条件的串拥有的不同子串个数。

示例1

输入:

baa
2
2
1

输出:

ba 3
a 1

示例2

输入:

ajddbijcebifijibhcfbicbegggfdedbahhcecbbfhabhdiedfjjbbbgcgebahhjehbigaeijehdjhbciaajhdcacgdiggegahbi
10
51
59
45
1
47
85
33
51
83
9

输出:

bifijibhcfbicbegggfdedbahhcecbbfhabhdiedfjjbbbgcgeb 1277
ajddbijcebifijibhcfbicbegggfdedbahhcecbbfhabhdiedfjjbbbgcge 1709
bfhabhdiedfjjbbbgcgebahhjehbigaeijehdjhbciaaj 994
a 1
cbbfhabhdiedfjjbbbgcgebahhjehbigaeijehdjhbciaaj 1084
jcebifijibhcfbicbegggfdedbahhcecbbfhabhdiedfjjbbbgcgebahhjehbigaeijehdjhbciaajhdcacgd 3554
bfhabhdiedfjjbbbgcgebahhjehbigaei 537
bifijibhcfbicbegggfdedbahhcecbbfhabhdiedfjjbbbgcgeb 1277
bifijibhcfbicbegggfdedbahhcecbbfhabhdiedfjjbbbgcgebahhjehbigaeijehdjhbciaajhdcacgdi 3388
abhdiedfj 44

说明:

|s|≤100000,q≤10,1≤k≤|s|

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 116ms, 内存消耗: 34096K, 提交时间: 2020-10-08 18:49:55

/*
 * @Author : Nightmare
 */
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define ls 2 * rt
#define rs 2 * rt + 1
#define gcd(a,b) __gcd(a,b)
#define eps 1e-8
#define lowbit(x) (x&(-x))
#define N 200005
#define M 10
#define mod 1000000007
#define inf 0x3f3f3f3f
struct SAM{
    static const int maxn = 2e5 + 5;
    int nxt[maxn][26], fail[maxn], fa[maxn], len[maxn], endpos[maxn];
    int root, tot, last, n; ll f[maxn], g[maxn];
    int ch[maxn][2];
    inline int newnode(int l){
        ch[tot][0] = ch[tot][1] = 0;
        fa[tot] = fail[tot] = -1; endpos[tot] = -1;
        for(int i = 0 ; i < 26 ; i ++) nxt[tot][i] = -1;
        len[tot ++] = l;
        return tot - 1;
    }
    inline void init(int mx){
        tot = 0; n = mx;
        for(int i = 1 ; i <= n ; i ++) f[i] = g[i] = 0;
        last = root = newnode(0);
    }
    inline void insert(int x, int id){
        int p = last, np = newnode(len[p] + 1);
        last = np; endpos[np] = id;
        while(p != -1 && nxt[p][x] == -1) nxt[p][x] = np, p = fa[p];
        if(p == -1) fa[np] = root;
        else{
            int q = nxt[p][x];
            if(len[q] == len[p] + 1) fa[np] = q;
            else{
                int nq = newnode(len[p] + 1);
                memcpy(nxt[nq], nxt[q], sizeof(nxt[q]));
                fa[nq] = fa[q]; fa[q] = fa[np] = nq;
                while(p != -1 && nxt[p][x] == q) nxt[p][x] = nq, p = fa[p];
            }
        }
    }
    inline void build(){
        for(int i = 0 ; i < tot ; i ++) fail[i] = fa[i];
    }
    inline int dir(int x){
        return ch[fa[x]][1] == x;
    }
    inline bool isroot(int x){
        return ch[fa[x]][0] != x && ch[fa[x]][1] != x;
    }
    inline void rotate(int x){
        int y = fa[x], z = fa[y], k = dir(x);
        if(!isroot(y)) ch[z][ch[z][1] == y] = x;
        else endpos[x] = endpos[y];
        ch[y][k] = ch[x][k ^ 1]; fa[ch[y][k]] = y;
        ch[x][k ^ 1] = y; fa[y] = x; fa[x] = z;
    }
    inline void splay(int x){
        for(int y = fa[x] ; !isroot(x) ; y = fa[x]){
            if(!isroot(y)) dir(y) == dir(x) ? rotate(y) : rotate(x);
            rotate(x);
        }
    }
    inline int access(int x){
        int p = 0;
        update(1, endpos[x], 1);
        while(x){
            splay(x);
            endpos[ch[x][1]] = endpos[x];
            ch[x][1] = p;
            if(p){
                if(endpos[x] != -1)
                    update(endpos[x] - len[x] + 1, endpos[x] - len[fa[x]], -1);
                endpos[x] = endpos[p];
            }
            p = x; x = fa[x];
        }
        return p;
    }
    inline void update(int l, int r, int v){
        r ++;
        for(int i = l ; i <= n ; i += lowbit(i)) f[i] += v, g[i] += l * v;
        for(int i = r ; i <= n ; i += lowbit(i)) f[i] -= v, g[i] -= r * v;
    }
    inline ll query(int l, int r){
        ll ans = 0; l --;
        for(int i = l ; i > 0 ; i -= lowbit(i)) ans -= f[i] * (l + 1), ans += g[i];
        for(int i = r ; i > 0 ; i -= lowbit(i)) ans += f[i] * (r + 1), ans -= g[i];
        return ans;
    }
}sam;
struct suffix_array {
    static const int maxn = 2e5 + 5;
    int sa[maxn], h[maxn], c[maxn], y[maxn], rk[maxn], str[maxn];
    inline void init(char *s, int n){
        for(int i = 0 ; i < n ; i ++) str[i] = s[i + 1] - 'a' + 1;
        str[n] = 0;
    }
    void build(int n, int m) {
        for (int i = 0; i < m; i++) c[i] = 0;
        for (int i = 0; i < n; i++) c[rk[i] = str[i]]++;
        for (int i = 1; i < m; i++) c[i] += c[i - 1];
        for (int i = n - 1; i >= 0; i--) sa[--c[rk[i]]] = i;
        for (int k = 1; k < n; k <<= 1) {
            int num = 0;
            for (int i = n - k; i < n; i++) y[num++] = i;
            for (int i = 0; i < n; i++) if (sa[i] >= k) y[num++] = sa[i] - k;
            for (int i = 0; i < m; i++) c[i] = 0;
            for (int i = 0; i < n; i++) c[rk[i]]++;
            for (int i = 1; i < m; i++) c[i] += c[i - 1];
            for (int i = n - 1; i >= 0; i--) sa[--c[rk[y[i]]]] = y[i];
            swap(rk, y); rk[sa[0]] = 0; num = 1;
            for (int i = 1; i < n; i++)
                rk[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? num - 1 : num++);
            if (num >= n) break;
            m = num;
        }
        for (int i = 0; i < n; i++) rk[sa[i]] = i;
    }
}sa;
int k[M], n, Q;
ll ans[M][N];
char s[N];
void out(int l, int r){
    char ch = s[r];
    s[r] = '\0';
    printf("%s", s + l);
    s[r] = ch;
}
inline void solve(){
    scanf("%s", s + 1); n = strlen(s + 1); sam.init(n);
    for(int i = 1 ; i <= n ; i ++) sam.insert(s[i] - 'a', i);
    sa.init(s, n);
    sam.build();
    sa.build(n + 1, 27);
    scanf("%d", &Q);
    for(int i = 0 ; i < Q ; i ++) scanf("%d", &k[i]);
    for(int i = 1, u = sam.root ; i <= n ; i ++){
        while(sam.nxt[u][s[i] - 'a'] == -1) u = sam.fail[u];
        u = sam.nxt[u][s[i] - 'a'];
        sam.access(u);
        for(int j = 0 ; j < Q ; j ++)
            if(i >= k[j])
                ans[j][i - k[j] + 1] = sam.query(i - k[j] + 1, i);
    }
    for(int i = 0 ; i < Q ; i ++){
        int pos = 1;
        for(int j = 2 ; j + k[i] - 1 <= n ; j ++){
            if(ans[i][j] > ans[i][pos]) pos = j;
            else if(ans[i][j] == ans[i][pos]){
                if(sa.rk[j - 1] < sa.rk[pos - 1])
                    pos = j;
            }
        }
        out(pos, pos + k[i]);
        printf(" %lld\n", ans[i][pos]);
    }
}
signed main(){
#ifndef ONLINE_JUDGE
    freopen("D:\\in.txt", "r", stdin);
#endif
    solve();
#ifndef ONLINE_JUDGE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 556ms, 内存消耗: 97040K, 提交时间: 2018-08-03 21:44:34

#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;

#define sz(x) (int((x).size()))

typedef long long LL;
const int MX=100005;
const int MC=26;
inline int get(char c)
{
	return c-'a';
}

struct Node;
typedef Node* PNode;

struct Node
{
	int l,r,pardp,ccnt;
	PNode par,slink;
	PNode chd[MC];

	inline int len()
	{
		return r-l;
	}

	inline int depth()
	{
		return pardp+len();
	}

	inline bool inEdge(int pos)
	{
		return pardp<=pos&&pos<depth();
	}

	bool DFS();
};

struct SuffixTree
{
	char*s;
	int dn,sn,jj;
	bool needWalk;
	PNode root,cur,need;
	Node d[MX*2];
	queue<PNode>que;
	LL tot;
	PNode newNode()
	{	d[dn]=Node();
		return&d[dn++];
	}

	void add_edge(PNode p,PNode q,int l,int r)
	{
		p->chd[get(s[l])]=q;
		p->ccnt++;
		q->par=p;
		q->pardp=p->depth();
		q->l=l,q->r=r;
	}

	void walk_down(int j,int i)
	{
		if(i<j) return;
		for(int h=j+cur->depth();!(cur->inEdge(i-j));h+=cur->len())cur=cur->chd[get(s[h])];
	}

	void add_slink()
	{
		if(need)need->slink=cur;
		need=0;
	}

	void extend(int i)
	{
		int k,pos;
		char c=s[i+1];
		PNode leaf,split;

		for(;jj<=i+1;jj++)
		{
			if(needWalk)
			{
				if(!cur->slink&&cur->par)cur=cur->par;
				cur=(cur->slink)?cur->slink:root;
				walk_down(jj,i);
			}
			needWalk=1;
			k=i-jj+1;
			if(k==cur->depth())
			{
				add_slink();
				if(cur->chd[get(c)])
				{
					cur=cur->chd[get(c)];
					needWalk=0;
					break;
				}
				leaf=newNode();
				add_edge(cur,leaf,i+1,sn);
				que.push(leaf);
			}
			else
			{
				pos=cur->l+(k-cur->pardp);
				if(s[pos]==c)
				{
					add_slink();
					if(pos!=i+1)
					{
						needWalk=0;
						break;
					}
				}
				else
				{
					split=newNode();
					leaf=newNode();
					add_edge(cur->par,split,cur->l,pos);
					cur->par->ccnt--;
					add_edge(split,cur,pos,cur->r);
					add_edge(split,leaf,i+1,sn);
					que.push(leaf);
					cur=split;
					add_slink();
					if(cur->depth()==1)cur->slink=root;
					else need=cur;
				}
			}
		}
		tot+=sz(que);
	}

	void erase(int i)
	{
		int k;
		PNode tmp;

		tmp=que.front();
		que.pop();
		while(!(tmp->ccnt))
		{
			if(cur==tmp)
			{
				k=(i-jj+1)-cur->pardp;
				tot-=min(cur->r,i+1)-cur->l-k;
				cur->l=i+1-k;
				cur->r=sn;
				que.push(cur);
				break;
			}
			tmp->par->chd[get(s[tmp->l])]=0;
			tmp->par->ccnt--;
			tot-=min(tmp->r,i+1)-tmp->l;
			tmp=tmp->par;
		}
		if(!(tmp->ccnt))
		{
			cur=cur->par;
			if(cur!=root)cur=cur->slink;
			walk_down(++jj,i);
			needWalk=0;
		}
	}

	void init(char *t,int tn)
	{
		s=t,sn=tn;
		dn=0;
		root=newNode();
		cur=newNode();
		add_edge(root,cur,0,sn);
		need=0;
		jj=1;
		needWalk=1;
		while(!que.empty())que.pop();
		que.push(cur);
		tot=1;
	}

	void build(char*t,int tn)
	{
		init(t,tn);
		for(int i=0;i<tn-1;i++)extend(i);
	}
};

char s[MX];
int n,k;
SuffixTree t1,t2;
LL a[MX],ans;
int st;

bool Node::DFS()
{
	if(!ccnt)
	{
		if(depth()<k) return 0;
		st=n-depth();
		return a[st]==ans;
	}
	for(int i=0;i<MC;i++)
	{
		PNode p=chd[i];
		if(!p)continue;
		if(p->DFS()) return 1;
	}
	return 0;
}

int main()
{
	int q,i;char c;
	scanf("%s",s);
	{	n=strlen(s);
		t1.build(s,n);
		for(scanf("%d",&q);q--;)
		{	scanf("%d",&k);
			t2.init(s,n);
			for(i=0;i<k-1;i++)t2.extend(i);
			a[0]=t2.tot;
			for(i=k;i<n;i++)
			{	t2.extend(i-1);
				t2.erase(i);
				a[i-k+1]=t2.tot;
			}
			ans=*max_element(a,a+n-k+1);
			st=-1;
			t1.root->DFS();
			c=s[st+k];
			s[st+k]=0;
			printf("%s %lld\n",s+st,ans);
			s[st+k]=c;
		}
	}
	return 0;
}

上一题