[ZJOI2013]丽洁体
还以为是序列自动机真是吓人
发现一个非常显然的事情,因为我们要的是\(A...B...C\),\(A\)一定要成为前缀,\(C\)一定要成为后缀,于是我们发现我们需要让\(A\)尽量靠前\(C\)尽量靠后
一是因为这样\(A\)和\(C\)去掉的位置尽量少,二来能留给\(B\)更多的空间
这里直接贪心就好了,先选择\(A\)第一个位置尽量靠前的,在选择第二个位置中,小于上一个选择的尽量靠前的,这样一直做下去就好了
之后搞\(B\),我们发现这里我们的贪心失效了,因为我们的贪心只能保证出现位置尽量靠前,而不能保证开始位置和结束位置相差最小
但是我们发现保证每一种字符串出现次数不超过\(500\),那不就随便做了吗
我们枚举\(B\)的第一个字符在\(T\)里出现的所有位置,之后贪心找到这个位置对应的最靠前的位置
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define re register
#define LL long long
#define ull unsigned long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int maxn=50005;
char S[15];
ull base=233;
int n,a,b,c,sz,lp,rp,tot;
std::vector<int> v[maxn];
int pos[maxn];
ull d[maxn],A[maxn],T[maxn],B[maxn],C[maxn];
inline ull getHash() {
ull now=0;
int len=strlen(S);
for(re int i=0;i<len;i++) now=now*base+S[i];
return now;
}
inline void init(){
do{scanf("%s",S);T[++n]=getHash();}while(getchar()==' ');
do{scanf("%s",S);A[++a]=getHash();}while(getchar()==' ');
do{scanf("%s",S);B[++b]=getHash();}while(getchar()==' ');
do{scanf("%s",S);C[++c]=getHash();}while(getchar()==' ');
}
inline int find(ull x) {
int l=1,r=sz;
while(l<=r) {
int mid=l+r>>1;
if(d[mid]==x) return mid;
if(d[mid]<x) l=mid+1;
else r=mid-1;
}
return 0;
}
int main() {
init();
for(re int i=1;i<=n;i++) d[i]=T[i];
std::sort(d+1,d+n+1);
sz=std::unique(d+1,d+n+1)-d-1;
for(re int i=1;i<=n;i++) {
int x=find(T[i]);
v[x].push_back(i);
}
lp=0;
for(re int i=1;i<=a;i++) {
int x=find(A[i]);
int l=0,r=v[x].size()-1,ans=0;
while(l<=r) {
int mid=l+r>>1;
if(v[x][mid]>lp) ans=mid,r=mid-1;
else l=mid+1;
}
lp=v[x][ans];
}
rp=n+1;
for(re int i=c;i;--i) {
int x=find(C[i]);
int l=0,r=v[x].size()-1,ans=0;
while(l<=r) {
int mid=l+r>>1;
if(v[x][mid]<rp) ans=mid,l=mid+1;
else r=mid-1;
}
rp=v[x][ans];
}
for(re int i=1;i<=sz;i++) v[i].clear();
for(re int i=lp+1;i<rp;i++) {
int x=find(T[i]);
v[x].push_back(i);
}
tot=lp-a+(n-rp+1-c);
for(re int i=1;i<=b;i++) pos[i]=find(B[i]);
int h=n;
for(re int i=0;i<v[pos[1]].size();i++) {
int now=v[pos[1]][i];
for(re int j=2;j<=b;j++) {
int x=pos[j];
int l=0,r=v[x].size()-1,ans=-1;
while(l<=r) {
int mid=l+r>>1;
if(v[x][mid]>now) ans=mid,r=mid-1;
else l=mid+1;
}
if(ans==-1) {now=2*n;break;}
now=v[x][ans];
}
h=min(h,now-v[pos[1]][i]+1-b);
}
printf("%d\n",tot+h);
return 0;
}