/*KMP算法核心思想并不难,但是各种版本总有细小的区别
每次复习都会产生疑问,又重蹈覆辙才豁然开朗

next数组:
目的:当子串pattern[i]不匹配时,转到next[i]继续匹配,从而保证主串不回溯
求解:next[i]的值即为pattern[0]~pattern[i-1],前面i个元素构成的串的最大公共前缀后缀
           根据递推关系:若当前字符匹配,则next[i+1]=next[i]+1 ,即最大公共前缀后缀+1

next[0]=-1 :
规定当比较第一个元素时,为了避免原地等待,设置-1
表示子串找不到合适的比较对象,主串要后移一位,子串从头开始比较
这其实也将其他位置的比较统一起来,因为其他位置若不匹配则继续比较,
比较的位置:i->next[i] ->next[next[i]]->...,直到最终i=-1 
(当然也有next[0]=0的版本,这是将整个next[ ]数组元素位置后移,
next[0]就无意义了,next[i]从1开始

允许重复匹配:允许两次匹配成功的串有公共部分
有多种写法:
1.i--,j=next[j-1] //假设上次未匹配成功,继续匹配,由于++过,所以要--
2.直接 j=nextTB[j] 因为其实在求next[]的时候可以多算一位next[m],
计算整个子串的最大公共前缀后缀,此时正好相当于有一个m+1位的子串匹配了前m位(m为子串长度)
3.i=i-j+1,j=0;//回溯到匹配成功的下一个字符从头开始匹配,不推荐,因为不符合KMP算法主串不回溯的思想

*/
#include <iostream>
#include<string> 
using namespace std;

const int MAXM=500000+10;
int nextTB[MAXM];
string pattern;
string text;

void getnext(string pattern){
    int j=0,m=pattern.size();
    nextTB[j]=-1;
    int i=nextTB[j];
    while(j<m){
        if(i==-1||pattern[j]==pattern[i]){//初始或者当前匹配值相同 
            i++;
            j++;
            nextTB[j]=i;//nextTB[j+1]=nextTB[j]+1 
        }
        else i=nextTB[i];//不匹配则继续比较,i->next[i] ->next[next[i]],直到最终i=-1 
    }
}

void kmpfind(string pattern,string text) {
    getnext(pattern);
    int n=text.size();
    int m=pattern.size();
    int j=0,i=0;
    int flag=0;
    while(i<n){//匹配text的每个字符 
        if(j==-1||pattern[j]==text[i]){
            i++;
            j++;
        }
        else j=nextTB[j];
        if(j==m){
            if(flag==1)cout<<" "<<i-j;
            else cout<<i-j;
            flag=1;
            j=nextTB[j];//允许字符重复匹配       
            //j=0;//不允许字符重复匹配
        }  
    }
    if(flag==0)cout<<-1;
}

int main() {
    getline(cin,text);
    getline(cin,pattern);
    kmpfind(pattern,text);
    return 0;
}