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;
}