【题解】Codeforces19C. Deletion of Repeats 后缀数组

给定一个字符串,长为 n ( 1 e 5 ) n(1e5) ,字符集 1 e 9 1e9 ,保证每个字符最多出现10次。

定义重复:长为偶数的子串,左半部分和右半部分完全相等。

每次选择最短、最靠左的一个重复,删除它的左半部分,以及这个重复左边的所有字符。

输出没有重复时的字符串。


每个字符最多出现10次,所以重复的个数一定不会超过 5 e 5 5e5

处理所有字符出现的位置,通过lcp判断是否出现重复,就找到了所有的重复。

对所有重复排序,然后遍历一遍,如果一个重复是合法的(子串没有被删掉一部分),就将其应用(删掉)。

后缀数组板子题吧。


我的垃圾后缀数组,居然不支持\0作为字符。

qwq。

建议先离散化。

/* LittleFall : Hello! */
#include <bits/stdc++.h>
using namespace std; using ll = long long; inline int read();
const int M = 100016, MOD = 1000000007;

namespace SA
{
    void st_init(int *arr, int n);
    
    /* 后缀数组 */
    int sa[M], rk[M], height[M]; //后缀三数组,sa和rk下标从0开始,height下标从1开始
    int t1[M], t2[M], c[M]; // 用于基数排序的三个辅助数组
    void build(int *str, int n, int m) // 构造后缀三数组,字符串下标从0开始,n表示长度,m表示字符集大小
    {  
        str[n] = 0;
        n++;  
        int i, j, p, *x = t1, *y = t2;  
        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]] = (y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]) ? p-1 : p++;  
            if(p >= n) break;  
            m = p;  
        }  
        n--;  
        for(int i = 0; i <= n; i++) rk[sa[i]] = i;  
        // for(int i=0; i<=n; ++i)
        // {
        // 	printf("%d %d %d\n",i,sa[i],rk[i] );
        // }
        for(int i=0, j=0, k=0; i < n; i++)  
        {   
            if(k) k--;  
            j = sa[rk[i]-1];  
            while(str[i+k]==str[j+k]) k++;  
            height[rk[i]] = k;  
        }  
        st_init(height, n);
    }

    /* ST表 */
    int lg[M], _n;
    int table[20][M];
    void st_init(int *arr, int n)
    {
        _n = n;
        if(!lg[0])
        {
            lg[0]=-1;
            for(int i=1;i<M;i++)
                lg[i]=lg[i/2]+1;
        }
        for(int i=1; i<=n; ++i)
            table[0][i] = arr[i];
        for(int i=1; i<=lg[n]; ++i)
            for(int j=1; j<=n; ++j)
                if(j+(1<<i)-1 <= n)
                    table[i][j] = min(table[i-1][j], table[i-1][j+(1<<(i-1))]);
    }
    // 查询第l个后缀和第r个后缀的LCP,下标从0开始
    int lcp(int l, int r)
    {
        if(l==r) return _n-l;
        l = rk[l], r = rk[r];
        if(l>r) swap(l,r);
        ++l;

        int t = lg[r-l+1];
        return min(table[t][l], table[t][r-(1<<t)+1]);
    }
};

int save[M];
//离散化
int dct[M];
int discretization(int n)
{
	int dcnt = 0;
	for(int i=0; i<n; ++i)
		dct[dcnt++] = save[i];
	sort(dct, dct+dcnt);
	dcnt = unique(dct, dct+dcnt) - dct;
	for(int i=0; i<n; ++i)
		save[i] = lower_bound(dct, dct+dcnt, save[i])-dct+1;
	return dcnt;
}
vector<int> ids[M];
int main(void)
{
	#ifdef _LITTLEFALL_
	freopen("in.txt","r",stdin);
    #endif

	int n = read();
	for(int i=0; i<n; ++i)
		save[i] = read();
	int m = discretization(n);
	//printf("save[0]=%d\n",save[0]);
	SA::build(save, n, m+1);
	for(int i=0; i<n; ++i)
		ids[save[i]].push_back(i);

	vector<pair<int,int>> qs; //差,起始位置
	for(int i=1; i<=m; ++i)
		for(auto id1:ids[i]) for(auto id2:ids[i]) if(id1<id2) //lazy
			if(id1<id2 && SA::lcp(id1,id2)>=id2-id1)
				qs.push_back({id2-id1, id1});
	sort(qs.begin(), qs.end());

	int cut = 0; //截取之后从哪里开始
	for(auto q:qs) if(q.second>=cut)
		cut = q.first+q.second;

	printf("%d\n",n-cut );
	for(int i=cut; i<n; ++i)
		printf("%d ",dct[save[i]-1] );

    return 0;
}

inline int read(){
    int x=0,f=1;char ch=getchar();
    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;
}
发布了375 篇原创文章 · 获赞 305 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/m0_37809890/article/details/103154582