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;
}
posted @ 2024-04-16 14:47  lty_ylzsx  阅读(9)  评论(1编辑  收藏  举报