Problem:
Score : 600 points

Problem Statement

Given are two strings s and t consisting of lowercase English letters. Determine if the number of non-negative integers i satisfying the following condition is finite, and find the maximum value of such i if the number is finite.

There exists a non-negative integer j such that the concatenation of i copies of t is a substring of the concatenation of j copies of s.

Notes

A string a is a substring of another string b if and only if there exists an integer x (0 \leq x \leq |b| - |a|) such that, for any y (1 \leq y \leq |a|), a_y = b_{x+y} holds.

We assume that the concatenation of zero copies of any string is the empty string. From the definition above, the empty string is a substring of any string. Thus, for any two strings s and t, i = 0 satisfies the condition in the problem statement.

Constraints

1 \leq |s| \leq 5 \times 10^5

1 \leq |t| \leq 5 \times 10^5

s and t consist of lowercase English letters.

Input

Input is given from Standard Input in the following format:

s
t

Output

If the number of non-negative integers i satisfying the following condition is finite, print the maximum value of such i; if the number is infinite, print -1.

Sample Input 1

abcabab
ab

Sample Output 1

3

The concatenation of three copies of t, ababab, is a substring of the concatenation of two copies of s, abcabababcabab, so i = 3 satisfies the condition.

On the other hand, the concatenation of four copies of t, abababab, is not a substring of the concatenation of any number of copies of s, so i = 4 does not satisfy the condition.

Similarly, any integer greater than 4 does not satisfy the condition, either. Thus, the number of non-negative integers i satisfying the condition is finite, and the maximum value of such i is 3.

Sample Input 2

aa
aaaaaaa

Sample Output 2

-1

For any non-negative integer i, the concatenation of i copies of t is a substring of the concatenation of 4i copies of s. Thus, there are infinitely many non-negative integers i that satisfy the condition.

Sample Input 3

aba
baaab

Sample Output 3

0

As stated in Notes, i = 0 always satisfies the condition.

Solution in Rust (1.15.1) (judge verdict: Accepted)

pub struct HashUnionFindSets<T: Eq + std::hash::Hash + std::fmt::Debug> {
    set_count: usize,
    items: std::collections::HashMap<T, UnionFindNode<T>>,
}
#[derive(Clone)]
enum UnionFindNodeInner<T: Eq + std::hash::Hash> {
    Root { len: usize },
    Child { parent: UnionFindNode<T> },
}
#[derive(Clone)]
struct UnionFindNode<T: Eq + std::hash::Hash>(
    std::rc::Rc<std::cell::RefCell<UnionFindNodeInner<T>>>,
    T,
);
impl<T: Eq + std::hash::Hash + Clone> UnionFindNode<T> {
    fn new(item: T) -> UnionFindNode<T> {
        UnionFindNode(
            std::rc::Rc::new(std::cell::RefCell::new(UnionFindNodeInner::Root { len: 1 })),
            item,
        )
    }
}
impl<T: Eq + std::hash::Hash> std::cmp::PartialEq for UnionFindNode<T> {
    fn eq(&self, other: &UnionFindNode<T>) -> bool {
        self.1 == other.1
    }
}
impl<T: Eq + std::hash::Hash> std::cmp::Eq for UnionFindNode<T> {}
impl<T: Eq + std::hash::Hash> std::hash::Hash for UnionFindNode<T> {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.1.hash(state);
    }
}
impl<T: Eq + std::hash::Hash + std::fmt::Debug + Clone> HashUnionFindSets<T> {
    pub fn new() -> HashUnionFindSets<T> {
        HashUnionFindSets {
            set_count: 0,
            items: std::collections::HashMap::new(),
        }
    }
    fn error_msg(items: &[&T]) -> String {
        assert!(items.len() == 1 || items.len() == 2);
        if items.len() == 1 {
            format!("no set contains {:?}", items[0])
        } else {
            format!(
                "no set contains {:?} and no set contains {:?}",
                items[0], items[1]
            )
        }
    }
    pub fn add(&mut self, item: T) -> bool {
        if self.items.contains_key(&item) {
            false
        } else {
            self.set_count += 1;
            self.items.insert(item.clone(), UnionFindNode::new(item));
            true
        }
    }
    pub fn items_len(&self) -> usize {
        self.items.len()
    }
    fn find(&self, item: &T) -> Option<(UnionFindNode<T>, usize)> {
        fn go<T: Eq + std::hash::Hash + Clone>(
            node: UnionFindNode<T>,
        ) -> (UnionFindNode<T>, usize) {
            let inner = node.0.as_ref().clone().into_inner();
            match inner {
                UnionFindNodeInner::Root { len } => (node, len),
                UnionFindNodeInner::Child { parent } => {
                    let (root, len) = go(parent);
                    let mut borrowed = node.0.borrow_mut();
                    *borrowed = UnionFindNodeInner::Child {
                        parent: root.clone(),
                    };
                    (root, len)
                }
            }
        }
        self.items.get(item).cloned().map(go)
    }
    pub fn count(&self) -> usize {
        self.set_count
    }
    pub fn len_of(&self, item: &T) -> Result<usize, String> {
        self.find(item)
            .map(|(_, len)| len)
            .ok_or_else(|| HashUnionFindSets::error_msg(&[item]))
    }
    pub fn set_eq(&self, item1: &T, item2: &T) -> Result<bool, String> {
        match (self.find(item1), self.find(item2)) {
            (Some((root1, _)), Some((root2, _))) => Ok(root1 == root2),
            (Some(_), None) => Err(HashUnionFindSets::error_msg(&[item2])),
            (None, Some(_)) => Err(HashUnionFindSets::error_msg(&[item1])),
            (None, None) => Err(HashUnionFindSets::error_msg(&[item1, item2])),
        }
    }
    pub fn unite(&mut self, item1: &T, item2: &T) -> Result<bool, String> {
        match (self.find(item1), self.find(item2)) {
            (Some((root1, len1)), Some((root2, len2))) => {
                if root1 == root2 {
                    Ok(false)
                } else {
                    self.set_count -= 1;
                    let (mut root, mut child, root_node) = if len1 < len2 {
                        (root2.0.borrow_mut(), root1.0.borrow_mut(), &root2)
                    } else {
                        (root1.0.borrow_mut(), root2.0.borrow_mut(), &root1)
                    };
                    *root = UnionFindNodeInner::Root { len: len1 + len2 };
                    *child = UnionFindNodeInner::Child {
                        parent: root_node.clone(),
                    };
                    Ok(true)
                }
            }
            (Some(_), None) => Err(HashUnionFindSets::error_msg(&[item2])),
            (None, Some(_)) => Err(HashUnionFindSets::error_msg(&[item1])),
            (None, None) => Err(HashUnionFindSets::error_msg(&[item1, item2])),
        }
    }
}
impl<T: Eq + std::hash::Hash + std::fmt::Debug + Clone> std::fmt::Debug for HashUnionFindSets<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        use std::collections::{HashMap, HashSet};
        let mut root_to_set = HashMap::new();
        for item in self.items.keys() {
            let root = self.find(item);
            let set = root_to_set.entry(root).or_insert(HashSet::new());
            set.insert(item);
        }
        let sets: Vec<HashSet<&T>> = root_to_set.into_iter().map(|(_, v)| v).collect();
        if sets.len() == 0 {
            write!(f, "{{}}")
        } else {
            write!(f, "{{{:?}", sets[0])?;
            for set in &sets[1..] {
                write!(f, ", {:?}", set)?;
            }
            write!(f, "}}")
        }
    }
}
impl<T: Eq + std::hash::Hash + std::fmt::Debug + Clone> std::iter::FromIterator<T>
    for HashUnionFindSets<T>
{
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> HashUnionFindSets<T> {
        let items = iter
            .into_iter()
            .map(|x| (x.clone(), UnionFindNode::new(x)))
            .collect::<std::collections::HashMap<_, _>>();
        HashUnionFindSets {
            set_count: items.len(),
            items: items,
        }
    }
}

pub trait Readable {
    type Output;
    fn words_count() -> usize;
    fn read_words(words: &[&str]) -> Result<Self::Output, String>;
}
#[macro_export]
macro_rules! readable {
    ( $ t : ty , $ words_count : expr , |$ words : ident | $ read_words : expr ) => {
        impl Readable for $t {
            type Output = $t;
            fn words_count() -> usize {
                $words_count
            }
            fn read_words($words: &[&str]) -> Result<$t, String> {
                Ok($read_words)
            }
        }
    };
}
readable!((), 1, |_ss| ());
readable!(String, 1, |ss| ss[0].to_string());
impl Readable for char {
    type Output = char;
    fn words_count() -> usize {
        1
    }
    fn read_words(words: &[&str]) -> Result<char, String> {
        let chars: Vec<char> = words[0].chars().collect();
        if chars.len() == 1 {
            Ok(chars[0])
        } else {
            Err(format!("cannot parse `{}` as a char", words[0]))
        }
    }
}
pub struct Chars();
impl Readable for Chars {
    type Output = Vec<char>;
    fn words_count() -> usize {
        1
    }
    fn read_words(words: &[&str]) -> Result<Vec<char>, String> {
        Ok(words[0].chars().collect())
    }
}
macro_rules ! impl_readable_for_ints { ( $ ( $ t : ty ) * ) => { $ ( impl Readable for $ t { type Output = Self ; fn words_count ( ) -> usize { 1 } fn read_words ( words : & [ & str ] ) -> Result <$ t , String > { use std :: str :: FromStr ; <$ t >:: from_str ( words [ 0 ] ) . map_err ( | _ | { format ! ( "cannot parse `{}` as {}" , words [ 0 ] , stringify ! ( $ t ) ) } ) } } ) * } ; }
impl_readable_for_ints ! ( i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 ) ;
macro_rules ! define_one_origin_int_types { ( $ new_t : ident $ int_t : ty ) => { # [ doc = " Converts 1-origin integer into 0-origin when read from stdin." ] # [ doc = "" ] # [ doc = " # Example" ] # [ doc = "" ] # [ doc = " ```no_run" ] # [ doc = " # #[macro_use] extern crate atcoder_snippets;" ] # [ doc = " # use atcoder_snippets::read::*;" ] # [ doc = " // Stdin: \"1\"" ] # [ doc = " read!(a = usize_);" ] # [ doc = " assert_eq!(a, 0);" ] # [ doc = " ```" ] # [ allow ( non_camel_case_types ) ] pub struct $ new_t ; impl Readable for $ new_t { type Output = $ int_t ; fn words_count ( ) -> usize { 1 } fn read_words ( words : & [ & str ] ) -> Result < Self :: Output , String > { <$ int_t >:: read_words ( words ) . map ( | n | n - 1 ) } } } ; ( $ new_t : ident $ int_t : ty ; $ ( $ inner_new_t : ident $ inner_int_t : ty ) ;* ) => { define_one_origin_int_types ! ( $ new_t $ int_t ) ; define_one_origin_int_types ! ( $ ( $ inner_new_t $ inner_int_t ) ;* ) ; } ; }
define_one_origin_int_types ! ( u8_ u8 ; u16_ u16 ; u32_ u32 ; u64_ u64 ; usize_ usize ) ;
macro_rules ! impl_readable_for_tuples { ( $ t : ident $ var : ident ) => ( ) ; ( $ t : ident $ var : ident ; $ ( $ inner_t : ident $ inner_var : ident ) ;* ) => { impl_readable_for_tuples ! ( $ ( $ inner_t $ inner_var ) ;* ) ; impl <$ t : Readable , $ ( $ inner_t : Readable ) ,*> Readable for ( $ t , $ ( $ inner_t ) ,* ) { type Output = ( <$ t >:: Output , $ ( <$ inner_t >:: Output ) ,* ) ; fn words_count ( ) -> usize { let mut n = <$ t >:: words_count ( ) ; $ ( n += <$ inner_t >:: words_count ( ) ; ) * n } # [ allow ( unused_assignments ) ] fn read_words ( words : & [ & str ] ) -> Result < Self :: Output , String > { let mut start = 0 ; let $ var = <$ t >:: read_words ( & words [ start .. start +<$ t >:: words_count ( ) ] ) ?; start += <$ t >:: words_count ( ) ; $ ( let $ inner_var = <$ inner_t >:: read_words ( & words [ start .. start +<$ inner_t >:: words_count ( ) ] ) ?; start += <$ inner_t >:: words_count ( ) ; ) * Ok ( ( $ var , $ ( $ inner_var ) ,* ) ) } } } ; }
impl_readable_for_tuples ! ( T8 x8 ; T7 x7 ; T6 x6 ; T5 x5 ; T4 x4 ; T3 x3 ; T2 x2 ; T1 x1 ) ;
pub trait ReadableFromLine {
    type Output;
    fn read_line(line: &str) -> Result<Self::Output, String>;
}
fn split_into_words(line: &str) -> Vec<&str> {
    #[allow(deprecated)]
    line.trim_right_matches('\n').split_whitespace().collect()
}
impl<T: Readable> ReadableFromLine for T {
    type Output = T::Output;
    fn read_line(line: &str) -> Result<T::Output, String> {
        let words = split_into_words(line);
        if words.len() != T::words_count() {
            return Err(format!(
                "line `{}` has {} words, expected {}",
                line,
                words.len(),
                T::words_count()
            ));
        }
        T::read_words(&words)
    }
}
macro_rules ! impl_readable_from_line_for_tuples_with_from_iterator { ( $ u : ident : $ ( + $ bound : path ) * => $ seq_in : ty , $ seq_out : ty ; $ t : ident $ var : ident ) => { impl <$ u : Readable > ReadableFromLine for $ seq_in where <$ u as Readable >:: Output : Sized $ ( + $ bound ) * { type Output = $ seq_out ; fn read_line ( line : & str ) -> Result <$ seq_out , String > { let n = $ u :: words_count ( ) ; let words = split_into_words ( line ) ; if words . len ( ) % n != 0 { return Err ( format ! ( "line `{}` has {} words, expected multiple of {}" , line , words . len ( ) , n ) ) ; } let mut result = Vec :: new ( ) ; for chunk in words . chunks ( n ) { match $ u :: read_words ( chunk ) { Ok ( v ) => result . push ( v ) , Err ( msg ) => { let flagment_msg = if n == 1 { format ! ( "word {}" , result . len ( ) ) } else { let l = result . len ( ) ; format ! ( "words {}-{}" , n * l + 1 , ( n + 1 ) * l ) } ; return Err ( format ! ( "{} of line `{}`: {}" , flagment_msg , line , msg ) ) ; } } } Ok ( result . into_iter ( ) . collect ( ) ) } } impl < T : Readable , $ u : Readable > ReadableFromLine for ( T , $ seq_in ) where <$ u as Readable >:: Output : Sized $ ( + $ bound ) * { type Output = ( T :: Output , $ seq_out ) ; fn read_line ( line : & str ) -> Result < Self :: Output , String > { let n = T :: words_count ( ) ; # [ allow ( deprecated ) ] let trimmed = line . trim_right_matches ( '\n' ) ; let words_and_rest : Vec <& str > = trimmed . splitn ( n + 1 , ' ' ) . collect ( ) ; if words_and_rest . len ( ) < n { return Err ( format ! ( "line `{}` has {} words, expected at least {}" , line , words_and_rest . len ( ) , n ) ) ; } let words = & words_and_rest [ .. n ] ; let empty_str = "" ; let rest = words_and_rest . get ( n ) . unwrap_or ( & empty_str ) ; Ok ( ( T :: read_words ( words ) ?, <$ seq_in >:: read_line ( rest ) ? ) ) } } } ; ( $ u : ident : $ ( + $ bound : path ) * => $ seq_in : ty , $ seq_out : ty ; $ t : ident $ var : ident , $ ( $ inner_t : ident $ inner_var : ident ) ,+ ) => { impl_readable_from_line_for_tuples_with_from_iterator ! ( $ u : $ ( + $ bound ) * => $ seq_in , $ seq_out ; $ ( $ inner_t $ inner_var ) ,+ ) ; impl <$ t : Readable , $ ( $ inner_t : Readable ) ,+ , $ u : Readable > ReadableFromLine for ( $ t , $ ( $ inner_t ) ,+ , $ seq_in ) where <$ u as Readable >:: Output : Sized $ ( + $ bound ) * { type Output = ( $ t :: Output , $ ( $ inner_t :: Output ) ,+ , $ seq_out ) ; fn read_line ( line : & str ) -> Result < Self :: Output , String > { let mut n = $ t :: words_count ( ) ; $ ( n += $ inner_t :: words_count ( ) ; ) + # [ allow ( deprecated ) ] let trimmed = line . trim_right_matches ( '\n' ) ; let words_and_rest : Vec <& str > = trimmed . splitn ( n + 1 , ' ' ) . collect ( ) ; if words_and_rest . len ( ) < n { return Err ( format ! ( "line `{}` has {} words, expected at least {}" , line , words_and_rest . len ( ) , n ) ) ; } let words = & words_and_rest [ .. n ] ; let empty_str = "" ; let rest = words_and_rest . get ( n ) . unwrap_or ( & empty_str ) ; let ( $ var , $ ( $ inner_var ) ,* ) = < ( $ t , $ ( $ inner_t ) ,+ ) >:: read_words ( words ) ?; Ok ( ( $ var , $ ( $ inner_var ) ,* , <$ seq_in >:: read_line ( rest ) ? ) ) } } } ; }
#[macro_export]
macro_rules ! readable_collection { ( $ u : ident => $ collection_in : ty , $ collection_out : ty ) => { impl_readable_from_line_for_tuples_with_from_iterator ! ( $ u : => $ collection_in , $ collection_out ; T8 x8 , T7 x7 , T6 x6 , T5 x5 , T4 t4 , T3 t3 , T2 t2 , T1 t1 ) ; } ; ( $ u : ident : $ ( $ bound : path ) ,* => $ collection_in : ty , $ collection_out : ty ) => { impl_readable_from_line_for_tuples_with_from_iterator ! ( $ u : $ ( + $ bound ) * => $ collection_in , $ collection_out ; T8 x8 , T7 x7 , T6 x6 , T5 x5 , T4 t4 , T3 t3 , T2 t2 , T1 t1 ) ; } }
readable_collection ! ( U => Vec < U >, Vec < U :: Output > ) ;
readable_collection ! ( U : Eq , std :: hash :: Hash => std :: collections :: HashSet < U >, std :: collections :: HashSet < U :: Output > ) ;
pub fn read<T: ReadableFromLine>() -> T::Output {
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).unwrap();
    T::read_line(&line).unwrap()
}
#[macro_export]
macro_rules ! read { ( ) => { let mut line = String :: new ( ) ; std :: io :: stdin ( ) . read_line ( & mut line ) . unwrap ( ) ; } ; ( $ pat : pat = $ t : ty ) => { let $ pat = read ::<$ t > ( ) ; } ; ( $ ( $ pat : pat = $ t : ty ) ,+ ) => { read ! ( ( $ ( $ pat ) ,* ) = ( $ ( $ t ) ,* ) ) ; } ; }
#[macro_export]
macro_rules ! readls { ( $ ( $ pat : pat = $ t : ty ) ,+ ) => { $ ( read ! ( $ pat = $ t ) ; ) * } ; }
pub fn readx<T: ReadableFromLine>() -> Vec<T::Output> {
    use std::io::{self, BufRead};
    let stdin = io::stdin();
    let result = stdin
        .lock()
        .lines()
        .map(|line_result| {
            let line = line_result.expect("read from stdin failed");
            T::read_line(&line).unwrap()
        })
        .collect();
    result
}
#[macro_export]
macro_rules ! readx_loop { ( |$ pat : pat = $ t : ty | $ body : expr ) => { use std :: io :: BufRead ; let stdin = std :: io :: stdin ( ) ; for line in stdin . lock ( ) . lines ( ) { let line = line . expect ( "read from stdin failed" ) ; let $ pat = <$ t >:: read_line ( & line ) . unwrap ( ) ; $ body } } ; ( |$ ( $ pat : pat = $ t : ty ) ,*| $ body : expr ) => { readx_loop ! ( | ( $ ( $ pat ) ,* ) = ( $ ( $ t ) ,* ) | $ body ) ; } ; }
pub fn readn<T: ReadableFromLine>(n: usize) -> Vec<T::Output> {
    use std::io::{self, BufRead};
    let stdin = io::stdin();
    let result: Vec<T::Output> = stdin
        .lock()
        .lines()
        .take(n)
        .map(|line_result| {
            let line = line_result.expect("read from stdin failed");
            T::read_line(&line).unwrap()
        })
        .collect();
    if result.len() < n {
        panic!(
            "expected reading {} lines, but only {} lines are read",
            n,
            result.len()
        );
    }
    result
}
#[macro_export]
macro_rules ! readn_loop { ( $ n : expr , |$ pat : pat = $ t : ty | $ body : expr ) => { use std :: io :: BufRead ; let stdin = std :: io :: stdin ( ) ; { let mut lock = stdin . lock ( ) ; for _ in 0 ..$ n { let mut line = String :: new ( ) ; lock . read_line ( & mut line ) . expect ( "read from stdin failed" ) ; let $ pat = <$ t >:: read_line ( & line ) . unwrap ( ) ; $ body } } } ; ( $ n : expr , |$ ( $ pat : pat = $ t : ty ) ,*| $ body : expr ) => { readn_loop ! ( $ n , | ( $ ( $ pat ) ,* ) = ( $ ( $ t ) ,* ) | $ body ) ; } ; }
pub trait Words {
    fn read<T: Readable>(&self) -> T::Output;
}
impl<'a> Words for [&'a str] {
    fn read<T: Readable>(&self) -> T::Output {
        T::read_words(self).unwrap()
    }
}
impl<'a> Words for &'a str {
    fn read<T: Readable>(&self) -> T::Output {
        T::read_words(&[self]).unwrap()
    }
}

#[derive(Clone)]
pub struct StepBy<I> {
    iter: I,
    step: usize,
    first_take: bool,
}
impl<I: Iterator> Iterator for StepBy<I> {
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        if self.first_take {
            self.first_take = false;
            self.iter.next()
        } else {
            self.iter.nth(self.step)
        }
    }
}
#[derive(Clone)]
pub struct LScan<I: Iterator, S: Clone, F: FnMut(&S, I::Item) -> S> {
    iter: I,
    state: Option<S>,
    f: F,
}
impl<I: Iterator, S: Clone, F> Iterator for LScan<I, S, F>
where
    F: FnMut(&S, I::Item) -> S,
{
    type Item = S;
    fn next(&mut self) -> Option<S> {
        if self.state.is_none() {
            return None;
        }
        let state_inner = self.state.take().unwrap();
        if let Some(item) = self.iter.next() {
            self.state = Some((self.f)(&state_inner, item));
        }
        Some(state_inner)
    }
}
pub struct Flatten<I: Iterator>
where
    I::Item: IntoIterator,
{
    outer_iter: I,
    inner_iter: Option<<<I as Iterator>::Item as IntoIterator>::IntoIter>,
}
impl<I, J> Iterator for Flatten<I>
where
    I: Iterator<Item = J>,
    J: IntoIterator,
{
    type Item = <<J as IntoIterator>::IntoIter as Iterator>::Item;
    fn next(&mut self) -> Option<J::Item> {
        loop {
            if let Some(inner_iter) = self.inner_iter.as_mut() {
                if let item @ Some(_) = inner_iter.next() {
                    return item;
                }
            }
            match self.outer_iter.next() {
                None => return None,
                Some(inner) => self.inner_iter = Some(inner.into_iter()),
            }
        }
    }
}
pub struct GroupBy<K: Eq, I: Iterator, F: FnMut(&I::Item) -> K> {
    cur: Option<(I::Item, K)>,
    iter: I,
    key_fn: F,
}
impl<K: Eq, I: Iterator, F: FnMut(&I::Item) -> K> Iterator for GroupBy<K, I, F> {
    type Item = (K, Vec<I::Item>);
    fn next(&mut self) -> Option<(K, Vec<I::Item>)> {
        let cur = self.cur.take();
        cur.map(|(item, key)| {
            let mut group = vec![item];
            loop {
                let next = self.iter.next();
                match next {
                    Some(next_item) => {
                        let next_key = (self.key_fn)(&next_item);
                        if key == next_key {
                            group.push(next_item);
                        } else {
                            self.cur = Some((next_item, next_key));
                            break;
                        }
                    }
                    None => {
                        self.cur = None;
                        break;
                    }
                }
            }
            (key, group)
        })
    }
}
pub trait IteratorExt: Iterator {
    fn step_by_(self, step: usize) -> StepBy<Self>
    where
        Self: Sized,
    {
        assert_ne!(step, 0);
        StepBy {
            iter: self,
            step: step - 1,
            first_take: true,
        }
    }
    fn for_each<F: FnMut(Self::Item)>(self, mut f: F)
    where
        Self: Sized,
    {
        for item in self {
            f(item);
        }
    }
    fn lscan<S: Clone, F>(self, state: S, f: F) -> LScan<Self, S, F>
    where
        Self: Sized,
        F: FnMut(&S, Self::Item) -> S,
    {
        LScan {
            iter: self,
            state: Some(state),
            f: f,
        }
    }
    fn get_unique(mut self) -> Option<Self::Item>
    where
        Self: Sized,
        Self::Item: Eq,
    {
        let first_opt = self.next();
        first_opt.and_then(|first| {
            if self.all(|item| item == first) {
                Some(first)
            } else {
                None
            }
        })
    }
    fn flatten(mut self) -> Flatten<Self>
    where
        Self: Sized,
        Self::Item: IntoIterator,
    {
        let inner_opt = self.next();
        Flatten {
            outer_iter: self,
            inner_iter: inner_opt.map(|inner| inner.into_iter()),
        }
    }
    fn group_by<K: Eq, F: FnMut(&Self::Item) -> K>(mut self, mut f: F) -> GroupBy<K, Self, F>
    where
        Self: Sized,
    {
        let next = self.next();
        GroupBy {
            cur: next.map(|item| {
                let key = f(&item);
                (item, key)
            }),
            iter: self,
            key_fn: f,
        }
    }
    fn join(mut self, sep: &str) -> String
    where
        Self: Sized,
        Self::Item: std::fmt::Display,
    {
        let mut result = String::new();
        if let Some(first) = self.next() {
            result.push_str(&format!("{}", first));
        }
        for s in self {
            result.push_str(&format!("{}{}", sep, s));
        }
        result
    }
    fn cat(self) -> String
    where
        Self: Sized,
        Self::Item: std::fmt::Display,
    {
        self.join("")
    }
}
impl<I: Iterator> IteratorExt for I {}
pub struct Unfold<T, F>
where
    F: FnMut(&T) -> Option<T>,
{
    state: Option<T>,
    f: F,
}
impl<T, F> Iterator for Unfold<T, F>
where
    F: FnMut(&T) -> Option<T>,
{
    type Item = T;
    fn next(&mut self) -> Option<T> {
        if self.state.is_none() {
            return None;
        }
        let state_inner = self.state.take().unwrap();
        self.state = (self.f)(&state_inner);
        Some(state_inner)
    }
}
pub fn unfold<T, F>(init: T, f: F) -> Unfold<T, F>
where
    F: FnMut(&T) -> Option<T>,
{
    Unfold {
        state: Some(init),
        f: f,
    }
}
pub struct Iterate<T, F>
where
    F: FnMut(&T) -> T,
{
    state: T,
    f: F,
}
impl<T, F> Iterator for Iterate<T, F>
where
    F: FnMut(&T) -> T,
{
    type Item = T;
    fn next(&mut self) -> Option<T> {
        use std::mem::swap;
        let mut state = (self.f)(&self.state);
        swap(&mut state, &mut self.state);
        Some(state)
    }
}
pub fn iterate<T, F>(init: T, f: F) -> Iterate<T, F>
where
    F: FnMut(&T) -> T,
{
    Iterate { state: init, f: f }
}

#[macro_export]
    #[cfg(local)]
    macro_rules! dbg {
    ( ) => {{
        use std::io::{self, Write};
        writeln!(io::stderr(), "{}: dbg", line!()).unwrap();
    }};
    ( $ e : expr ) => {{
        use std::io::{self, Write};
        let result = $e;
        writeln!(
            io::stderr(),
            "{}: {} = {:?}",
            line!(),
            stringify!($e),
            result
        )
            .unwrap();
        result
    }};
}
#[macro_export]
#[cfg(not(local))]
macro_rules! dbg {
    ( ) => {};
    ( $ e : expr ) => {
        $e
    };
}

pub type RollingHashBase = u64;
mod rolling_hash_internal {
    use super::RollingHashBase;
    pub const ROLL: RollingHashBase = 1154491469;
    pub const MOD: RollingHashBase = 4290357497;
    pub fn pow(base: RollingHashBase, exp: RollingHashBase) -> RollingHashBase {
        if exp == 0 {
            1
        } else {
            let pow_half = pow(base, exp / 2);
            if exp % 2 == 0 {
                (pow_half * pow_half) % MOD
            } else {
                (base * pow_half % MOD) * pow_half % MOD
            }
        }
    }
}
pub trait RollingHash {
    fn rolling_hash(&self) -> RollingHashValue<Self>;
    fn prefix_rolling_hash(&self) -> PrefixRollingHash<Self>;
}
impl RollingHash for [u8] {
    fn rolling_hash(&self) -> RollingHashValue<[u8]> {
        use self::rolling_hash_internal::*;
        let value = self.iter().fold(0u64, |acc, &next| {
            (acc * ROLL + next as RollingHashBase) % MOD
        });
        RollingHashValue {
            len: self.len(),
            value: value,
            seq_type: std::marker::PhantomData,
        }
    }
    fn prefix_rolling_hash(&self) -> PrefixRollingHash<[u8]> {
        use self::rolling_hash_internal::*;
        let prefix_hash = self
            .iter()
            .lscan(0 as RollingHashBase, |&acc, &next| {
                (acc * ROLL + next as RollingHashBase) % MOD
            })
            .collect();
        PrefixRollingHash {
            prefix_hash: prefix_hash,
            seq_type: std::marker::PhantomData,
        }
    }
}
pub struct RollingHashValue<T: ?Sized + RollingHash> {
    len: usize,
    value: RollingHashBase,
    seq_type: std::marker::PhantomData<T>,
}
impl<T: ?Sized + RollingHash> Clone for RollingHashValue<T> {
    fn clone(&self) -> Self {
        RollingHashValue {
            len: self.len,
            value: self.value,
            seq_type: self.seq_type.clone(),
        }
    }
}
impl<T: ?Sized + RollingHash> Copy for RollingHashValue<T> {}
impl<T: ?Sized + RollingHash> RollingHashValue<T> {
    pub fn len(&self) -> usize {
        self.len
    }
    pub fn value(&self) -> RollingHashBase {
        self.value
    }
}
pub struct PrefixRollingHash<T: ?Sized + RollingHash> {
    prefix_hash: Vec<RollingHashBase>,
    seq_type: std::marker::PhantomData<T>,
}
impl<T: ?Sized + RollingHash> PrefixRollingHash<T> {
    pub fn len(&self) -> usize {
        self.prefix_hash.len() - 1
    }
    pub fn matches_at(&self, pattern: RollingHashValue<T>, index: usize) -> Option<bool> {
        use self::rolling_hash_internal::*;
        let hash_right = match self.prefix_hash.get(index + pattern.len()) {
            Some(&hash) => hash,
            None => return None,
        };
        let hash_left = self.prefix_hash[index];
        let m = pow(ROLL, pattern.len() as RollingHashBase);
        Some((hash_right + MOD - (hash_left * m % MOD)) % MOD == pattern.value())
    }
    pub fn matches<'a>(&'a self, pattern: RollingHashValue<T>) -> RollingHashMatches<'a, T> {
        use self::rolling_hash_internal::*;
        RollingHashMatches {
            prefix_hash: self,
            pattern: pattern,
            m: pow(ROLL, pattern.len() as RollingHashBase),
            index: 0,
        }
    }
}
pub struct RollingHashMatches<'a, T: 'a + ?Sized + RollingHash> {
    prefix_hash: &'a PrefixRollingHash<T>,
    pattern: RollingHashValue<T>,
    m: RollingHashBase,
    index: usize,
}
impl<'a, T: ?Sized + RollingHash> Iterator for RollingHashMatches<'a, T> {
    type Item = usize;
    fn next(&mut self) -> Option<usize> {
        use self::rolling_hash_internal::*;
        while let Some(hash_right) = self
            .prefix_hash
            .prefix_hash
            .get(self.index + self.pattern.len())
        {
            let old_index = self.index;
            self.index += 1;
            let hash_left = self.prefix_hash.prefix_hash[old_index];
            let hash = (hash_right + MOD - (hash_left * self.m % MOD)) % MOD;
            if hash == self.pattern.value() {
                return Some(old_index);
            }
        }
        None
    }
}

fn solve(s: &str, t: &str) -> Option<usize> {
    let mut haystack: Vec<u8> = s.bytes().collect();
    haystack.extend(s.bytes());
    while haystack.len() < t.len() * 2 {
        haystack.extend(s.bytes());
    }
    let haystack = haystack.prefix_rolling_hash();
    let needle = t.as_bytes().rolling_hash();

    let mut connectivity: HashUnionFindSets<usize> = (0..s.len()).collect();
    for i in haystack.matches(needle).take_while(|&i| i < s.len()) {
        if !connectivity.unite(&i, &((i + needle.len()) % s.len())).unwrap() {
            return None;
        }
    }

    Some((0..s.len()).map(|i| connectivity.len_of(&i).unwrap() - 1).max().unwrap())
}

fn main() {
    readls!(s = String, t = String);
    match solve(&s, &t) {
        Some(ans) => println!("{}", ans),
        None => println!("-1")
    }
}