CF955D Scissors
\(CF955D\ \ Scissors\)
题意
给定串 \(s,t\),给一个 \(k\).用一把2k剪刀
从 \(s\) 上剪下两个长为 \(k\) 的子串拼起来(不重叠),判断是否存在一种解法使得拼出的串包含 \(t\).
做题历程
难绷,调了一个下午最后发现是个纸张错误 \(\dots\)
思路分析
此题可以哈希水过,我们预处理出串 \(t\) 的每个前缀在 \(s\) 中出现的最早位置,和每个后缀出现的最晚位置。对于每个前缀的处理,在 \(s\) 中暴匹,显然是 \(O(n\times m)\) 的,过不去。但是我们发现有个神奇的单调性——
设 \(l[i]\) 为第 \(i\) 个前缀在 \(s\) 中最早出现的位置,显然若 \(j>i\),必然有 \(l[j]>l[i]\),如果有解的话。
得出预处理:
int l[N],r[N];
void init()
{
int spx=k;
for(int i=1;i<=m;i++) l[i]=n+1;
for(int i=1;i<=min(m,k);i++){
for(;spx<=n&&hashs(spx-i+1,spx)!=t_hash[i];spx++);
if(hashs(k-i+1,k)==t_hash[i]) spx=k;
l[i]=spx;
}
spx=n-k+1;
for(int i=1;i<=min(m,k);i++){
for(;spx>=1&&hashs(spx,spx+i-1)!=hasht(m-i+1,m);spx--);
if(hashs(n-k+1,n-k+i)==hasht(m-i+1,m)) spx=n-k+1;
r[m-i+1]=spx;
}
}
接下来肆意匹配即可,但是要注意一点小特判。
-
如果在串 \(s\) 中找到了 \(t\),此时一定有解,只不过是它是否是被拼起来的。如果我们先找 \(t\),我们发现这很难判(很麻烦.麻烦.mafan...),所以我们换一种策略.
-
我们先枚举 \(t\) 的断点找前后缀匹配,然后再找整串 \(t\),对于 \([k+1,n-k+1]\) 范围内的我们一定已经匹完了,所以我只要找 \([1,k] \bigcup [n-k+1,n]\) 范围内即可,如果找到,我们发现答案一定是 \(1,k+1\) 和 \(n-2\times k+1,n-k+1\).
\(AC\ \ Code\)
#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
#define read read()
#define pt puts("")
#define wr puts("Yes"),write(ans1),putchar(' '),write(ans2)
inline int read
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=getchar();
return f*x;
}
void write(int x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
return;
}
#define base 233
#define N 500010
int n,m,k;
char s[N],t[N];
int s_hash[N],t_hash[N];
int powb[N];
int hashs(int ll,int rr){return (s_hash[rr]-(s_hash[ll-1]*powb[rr-ll+1]));}
int hasht(int ll,int rr){return (t_hash[rr]-(t_hash[ll-1]*powb[rr-ll+1]));}
int l[N],r[N];
void init()
{
int spx=k;
for(int i=1;i<=m;i++) l[i]=n+1;
for(int i=1;i<=min(m,k);i++){
for(;spx<=n&&hashs(spx-i+1,spx)!=t_hash[i];spx++);
if(hashs(k-i+1,k)==t_hash[i]) spx=k;
l[i]=spx;
}
spx=n-k+1;
for(int i=1;i<=min(m,k);i++){
for(;spx>=1&&hashs(spx,spx+i-1)!=hasht(m-i+1,m);spx--);
if(hashs(n-k+1,n-k+i)==hasht(m-i+1,m)) spx=n-k+1;
r[m-i+1]=spx;
}
}
int ans1,ans2;
signed main()
{
n=read;m=read;k=read;
if(n<(k<<1)||m>(k<<1)){puts("No");return 0;}
powb[0]=1;for(int i=1;i<=n;i++) powb[i]=powb[i-1]*base;
scanf(" %s",s+1);
scanf(" %s",t+1);
for(int i=1;i<=n;i++) s_hash[i]=(s_hash[i-1]*base+(s[i]-'a'+1));
for(int i=1;i<=m;i++) t_hash[i]=(t_hash[i-1]*base+(t[i]-'a'+1));
init();
for(int i=1;i<=m-1;i++){
if(l[i]!=n+1&&r[i+1]){
if(r[i+1]>l[i]){
ans1=l[i]-k+1;
ans2=r[i+1];
wr;return 0;
}
}
}
if(k>=m){
for(int i=1;i<=k;i++){
if(hashs(i,i+m-1)==t_hash[m]){
ans1=1,ans2=k+1;
wr;return 0;
}
}
for(int i=n-k+1;i<=n;i++){
if(hashs(i,i+m-1)==t_hash[m]){
ans1=n-2*k+1,ans2=n-k+1;
wr;return 0;
}
}
}
puts("No");
return 0;
}