给定一个字符串,长为 ,字符集 ,保证每个字符最多出现10次。
定义重复:长为偶数的子串,左半部分和右半部分完全相等。
每次选择最短、最靠左的一个重复,删除它的左半部分,以及这个重复左边的所有字符。
输出没有重复时的字符串。
每个字符最多出现10次,所以重复的个数一定不会超过 。
处理所有字符出现的位置,通过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;
}