Problem:
Score : 900 points

Problem Statement

Let x be a string of length at least 1.
We will call x a good string, if for any string y and any integer k (k \geq 2), the string obtained by concatenating k copies of y is different from x.
For example, a, bbc and cdcdc are good strings, while aa, bbbb and cdcdcd are not.

Let w be a string of length at least 1.
For a sequence F=(\,f_1,\,f_2,\,...,\,f_m) consisting of m elements,
we will call F a good representation of w, if the following conditions are both satisfied:

For any i \, (1 \leq i \leq m), f_i is a good string.

The string obtained by concatenating f_1,\,f_2,\,...,\,f_m in this order, is w.

For example, when w=aabb, there are five good representations of w:

(aabb)

(a,abb)

(aab,b)

(a,ab,b)

(a,a,b,b)

Among the good representations of w, the ones with the smallest number of elements are called the best representations of w.
For example, there are only one best representation of w=aabb: (aabb).

You are given a string w. Find the following:

the number of elements of a best representation of w

the number of the best representations of w, modulo 1000000007 \, (=10^9+7)

(It is guaranteed that a good representation of w always exists.)

Constraints

1 \leq |w| \leq 500000 \, (=5 \times 10^5)

w consists of lowercase letters (a-z).

Partial Score

400 points will be awarded for passing the test set satisfying 1 \leq |w| \leq 4000.

Input

The input is given from Standard Input in the following format:

w

Output

Print 2 lines.

In the first line, print the number of elements of a best representation of w.

In the second line, print the number of the best representations of w, modulo 1000000007.

Sample Input 1

aab

Sample Output 1

1
1

Sample Input 2

bcbc

Sample Output 2

2
3

In this case, there are 3 best representations of 2 elements:

(b,cbc)

(bc,bc)

(bcb,c)

Sample Input 3

ddd

Sample Output 3

3
1

Solution in C++14 (GCC 5.4.1) (judge verdict: Accepted)

#include <bits/stdc++.h>
  
#define FOR(i,a,b) for( ll i = (a); i < (ll)(b); i++ )
#define REP(i,n) FOR(i,0,n)
#define YYS(x,arr) for(auto& x:arr)
#define ALL(x) (x).begin(),(x).end()
#define SORT(x) sort( (x).begin(),(x).end() )
#define REVERSE(x) reverse( (x).begin(),(x).end() )
#define UNIQUE(x) (x).erase( unique( ALL( (x) ) ) , (x).end() )
#define PW(x) (1LL<<(x))
#define SZ(x) ((ll)(x).size())
#define SHOW(x) cout << #x << " = " << x << endl
 
#define pb emplace_back
#define fi first
#define se second

using namespace std;
 
typedef long double ld;
typedef long long int ll;
typedef pair<int,int> pi;
typedef pair<ll,ll> pl;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<bool> vb;
typedef vector<ld> vd;
typedef vector<pi> vpi;
typedef vector<pl> vpl;
typedef vector<vpl> gr;
typedef vector<vl> ml;
typedef vector<vd> md;
typedef vector<vi> mi;
 
const ll INF = (ll)1e9 + 10;
const ll INFLL = (ll)1e18 + 10;
const ld EPS = 1e-8;
const ll MOD = 1e9+7;

template<class T> T &chmin( T &a , const T &b ){ return a = min(a,b); }
template<class T> T &chmax( T &a , const T &b ){ return a = max(a,b); }
template<class T> inline T sq( T a ){ return a * a; }
ll in(){ ll x; scanf( "%lld\n" , &x ); return x; }
 
// head

char cs[1000010];
string stin(){ scanf( "%s" , cs ); return cs; }
 
struct SA : public vi{
  int n, k;
  vi rank, tmp;
  
  bool compare( int i , int j ){
    if( rank[i] != rank[j] ) return rank[i] < rank[j];
 
    int ri = i + k <= n ? rank[i+k] : -1;
    int rj = j + k <= n ? rank[j+k] : -1;
    return ri < rj;
  }
 
  struct Compare_SA{
    SA *sa;
    Compare_SA( SA *s ) : sa(s) {}
    bool operator() ( const int &i , const int &j ){
      return sa->compare( i , j );
    }
  };
 
  void init( string S ){
    n = S.length();
 
    resize( n+1 );
    rank = tmp = vi( n+1 );
    REP( i , n+1 ){
      at(i) = i;
      rank[i] = i < n ? S[i] : -1;
    }
 
    for( k = 1; k <= n; k *= 2 ){
      sort( begin() , end() , Compare_SA(this) );
 
      tmp[at(0)] = 0;
      FOR( i , 1 , n+1 )
	tmp[at(i)] = tmp[at(i-1)] + (compare(at(i-1),at(i))?1:0);
 
      REP( i , n+1 ) rank[i] = tmp[i];
    }
  }
};
 
struct LCP : public vi{
  void init( string S , const SA &sa ){
    int n = S.length();
 
    vi rank(n+1);
    REP( i , n+1 ) rank[sa[i]] = i;
 
    int h = 0;
    resize( n , 0 );
    REP( i , n ){
      int j = sa[rank[i]-1];
 
      if( h > 0 ) h--;
      for( ; j+h < n && i+h < n; h++ ) if( S[j+h] != S[i+h] ) break;
 
      at(rank[i]-1) = h;
    }
  }
};
 
template<class T>
class MinOp{
public:
  T operator () ( T a , T b ){ return min( a , b ); }
};
template<class T>
class MaxOp{
public:
  T operator () ( T a , T b ){ return max( a , b ); }
};
 
template<typename T, class OpFunc>
struct Segtree{
  T ID;
  vector<T> node;
  int size;
  OpFunc op;
  void init( int n , OpFunc opfunc , T identity ){
    op = opfunc;
    ID = identity;
    size = 1;
    while( size < n ) size *= 2;
    node = vector<T>( size*2-1 , ID );
  }
  void update( int k , T x ){
    k += size-1;
    node[k] = x;
    while( k > 0 ){
      k = (k-1)/2;
      node[k] = op( node[k*2+1] , node[k*2+2] );
    }
  }
  T query( int a , int b , int k , int l , int r ){
    if( a <= l && r <= b ){
      return node[k];
    } else if( b <= l || r <= a ){
      return ID;
    } else {
      T chl = query( a , b , k*2+1 , l , (l+r)/2 );
      T chr = query( a , b , k*2+2 , (l+r)/2 , r );
      return op( chl , chr );
    }
  }
  T query( int a , int b ){
    return query( a , b , 0 , 0 , size );
  }
  T get( int a ){
    return node[a+size-1];
  }
};

struct RangeLCP{
  SA sa;
  LCP lcp;
  Segtree<int,MinOp<int> > seg;
  void init( string s ){
    sa.init( s );
    lcp.init( s , sa );
    seg.init( SZ(s) , MinOp<int>() , INF );
    REP( i , SZ(s) ){
      seg.update( i , lcp[i] );
    }
  }
  int sa_query( int l , int r ){
    return seg.query( l , r );
  }
  int pos_query( int l , int r ){
    int a = sa.rank[l];
    int b = sa.rank[r];
    if( a > b ){
      swap( a , b );
    }
    return seg.query( a , b );
  }
};
 
int n;
string s, rs;
int p;

RangeLCP lcp, rlcp;

bool ng[1000010];

int main(){
 
  rs = s = stin();
  n = SZ(s);
  REVERSE( rs );

  lcp.init( s );
  rlcp.init( rs );
  
  FOR( i , 1 , n+1 ){
    if( n % i != 0 ){
      continue;
    }
    if( lcp.pos_query( 0 , i ) == n-i ){
      p = i;
      break;
    }
  }

  if( p == 1 ){
    cout << n << endl;
    cout << 1 << endl;
  } else if( p == n ){
    cout << 1 << endl;
    cout << 1 << endl;
  } else {
    FOR( i , 1 , n+1 ){
      int r = lcp.pos_query( 0 , i );
      for( int j = i; j <= r; j += i ){
	ng[i+j] = true;
      }
    }

    FOR( i , 1 , n+1 ){
      int r = rlcp.pos_query( 0 , i );
      for( int j = i; j <= r; j += i ){
	ng[n-(i+j)] = true;
      }
    }
    
    int ans = 0;
    FOR( i , 1 , n ){
      if( !ng[i] ){
	ans++;
      }
    }
    cout << 2 << endl;
    cout << ans << endl;
  }
  
  
  return 0;
}