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; }
分类:
字符串
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现