CodeForces 955D Scissors(字符串哈希)

 

D. Scissors

time limit per test:1 second

memory limit per test:256 megabytes

input:standard input

output:standard output

Jenya has recently acquired quite a useful tool — k-scissors for cutting strings. They are generally used for cutting out two non-intersecting substrings of length k from an arbitrary string s (its length should be at least 2·k in order to perform this operation) and concatenating them afterwards (preserving the initial order). For example, with the help of 2-scissors you can cut ab and de out of abcde and concatenate them into abde, but not ab and bc since they're intersecting.

It's a nice idea to test this tool before using it in practice. After looking through the papers, Jenya came up with two strings s and t. His question is whether it is possible to apply his scissors to string s such that the resulting concatenation contains t as a substring?

Input

The first line contains three integers n, m, k (2 ≤ m ≤ 2·k ≤ n ≤ 5·105) — length of s, length of t and the aforementioned scissors' parameter correspondingly.

The next two lines feature s and t consisting of lowercase latin letters.

Output

If there is no answer, print «No».

Otherwise print «Yes» and two integers L and R denoting the indexes where cutted substrings start (1-indexed). If there are several possible answers, output any.

Examples

Input

Copy

7 4 3
baabaab
aaaa

Output

Yes
1 5

Input

Copy

6 3 2
cbcbcb
bcc

Output

Yes
2 5

Input

Copy

7 5 3
aabbaaa
aaaaa

Output

No

Note

In the first sample case you can cut out two substrings starting at 1 and 5. The resulting string baaaab contains aaaa as a substring.

In the second sample case the resulting string is bccb.

 

 

 

       学多了高级的东西,别忘了简单的……

      大致题意,给出一个字符串,你有一把剪刀可以把字符串剪成两个不想交的长度为K的字符串,然后把两个拼起来。现在要你给出一种剪法使得拼接之后的字符串包含另一个新的字符串。

 

 

       其实不用想什么高级的算法,直接暴力即可。考虑第二个字符串的每一个前缀和后缀,我可以找到起点最左(右)的一个点,使得从这个点开始的长度为k的串的后(前)缀是我们要求的前缀和后缀。寻找的话利用双指针很快,1~i-1的前缀的位置求出来之后,1~i的前缀的位置肯定在1~i-1之后,然后一个个移动,判断两个字符串是否相等。消耗时间的就是在判断两个字符串是否相等的问题,这里直接用字符串哈希即可,即对于每一个字符串,把他对应为一个b进制下的数,对于纯字母的字符串一般来说b大于26。但是为了避免哈希冲突,我们改变了key而且采用了两个key组成的pair作为哈希值,基本保证不会冲突。最后时间复杂度是O(N)。

        最后,对于m<K的情况要额外讨论,具体见代码:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ULL unsigned long long
#define N 500010
using namespace std;

int n,m,k,lpos[N],rpos[N];
char s[N],t[N];

struct String_Hash
{
    ULL Hs[N],hs[N],p[N],P[N];

    void ins(char *s)
    {
        p[0]=P[0]=1;
        Hs[0]=hs[0]=s[0]-'a';
        for(int i=1;s[i];i++)
        {
            Hs[i]=Hs[i-1]*29+s[i]-'a';
            hs[i]=hs[i-1]*17+s[i]-'a';
            P[i]=P[i-1]*29;p[i]=p[i-1]*17;
        }

    }

    pair<ULL,ULL> Hash(int l,int r)
    {
        ULL tmp1=Hs[r],tmp2=hs[r];
        tmp1-=Hs[l-1]*P[r-l+1];
        tmp2-=hs[l-1]*p[r-l+1];
        return make_pair(tmp1,tmp2);
    }

} S,T;

void solve(int &l,int &r,int &flag)
{
    int pos=0;
    for(int i=0;i<m&&i<k;i++)
    {
        while(pos<i) pos++;
        for(;pos<n;pos++)
            if (S.Hash(pos-i,pos)==T.Hash(0,i)) break;
    }
    if (pos+k<n)
    {
        flag=1,l=max(1,pos-k+1);
        r=max(pos,k-1)+2; return;
    }
    pos=n-1;
    for(int i=0;i<m&&i<k;i++)
    {
        while(n-pos<i) pos--;
        for(;pos>=0;pos--)
            if (S.Hash(pos,pos+i)==T.Hash(m-1-i,m-1)) break;
    }
    if (pos-k>=0)
    {
        flag=1,l=min(n-k,pos)-k+1;
        r=min(n-k,pos)+1; return;
    }
}

int main()
{
    cin>>n>>m>>k;
    scanf("%s%s",s,t);
    S.ins(s);T.ins(t);
    memset(lpos,-1,sizeof(lpos));
    memset(rpos,-1,sizeof(rpos));
    int pos=k-1;
    for(int i=0;i<m&&i<k;i++)
    {
        while(pos<i) pos++;
        for(;pos<n;pos++)
            if (S.Hash(pos-i,pos)==T.Hash(0,i)) break;
        if (S.Hash(k-i-1,k-1)==T.Hash(0,i)) pos=k-1;
        lpos[i]=pos;
    }
    pos=n-k;
    for(int i=0;i<m&&i<k;i++)
    {
        while(n-pos<i) pos--;
        for(;pos>=0;pos--)
            if (S.Hash(pos,pos+i)==T.Hash(m-1-i,m-1)) break;
        if (S.Hash(n-k,n-k+i)==T.Hash(m-1-i,m-1)) pos=n-k;
        rpos[m-1-i]=pos;
    }
    int l,r,flag=0;
    for(int i=0;i<n-1;i++)
        if (lpos[i]!=-1&&rpos[i+1]!=-1&&lpos[i]<rpos[i+1])
        {
            l=lpos[i]-k+2;
            r=rpos[i+1]+1;
            flag=1; break;
        }
    if (k>=m&&!flag) solve(l,r,flag);
    if (flag) printf("Yes\n%d %d\n",l,r);
         else puts("No");
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值