#include<bits/stdc++.h>
using namespace std;
using Int = signed;

template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}


struct CartesianTree{
  int n;
  vector<int> P,L,R;
  CartesianTree(int n):n(n),P(n,-1),L(n,-1),R(n,-1){}

  template<typename T>
  int build(vector<T> v){
    int p=0;
    for(int i=1;i<n;i++){
      if(v[p]<=v[i]){
	R[p]=i;
	P[i]=p;
	p=i;
	continue;
      }
      while(~P[p]&&v[i]<v[P[p]]) p=P[p];
      P[i]=P[p];
      if(~P[i]) R[P[i]]=i;
      L[i]=p;
      P[p]=i;
      p=i;
    }
    while(~P[p]) p=P[p];
    return p;
  }
};


struct LCA{
  const int lg = 18;
  const int sz = 1<<lg;
  const int ms = sz-1;
  int n;
  vector<int> P,D,E,A,B,T,ht;
  vector<vector<int> > G,dat;
  LCA(int n):
    n(n),P(n,-1),D(n),E(n*2,0),A(n*2,-1),B(n*2/lg+1),T(sz,0),G(n){}

  void add_edge(int u,int v){
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  void dfs(int v,int p,int d,int &k){
    D[v]=k;
    A[k]=P[v]=p;
    E[k++]=d;
    for(int u:G[v])
      if(u!=p) dfs(u,v,d+1,k);
    A[k]=P[v];
    E[k++]=d-1;
  }

  // if it need leftmost, then add: if(E[i]==E[j]) return i<j?i:j;
  inline int comp(int i,int j){return E[i]<E[j]?i:j;};
  inline int comp(int i,int j,int k){return comp(comp(i,j),k);};
  
  void build(int r=0){
    int k=0;
    dfs(r,-1,1,k);
    
    B[0]=1;
    for(int i=1;i<n*2;i++) B[i/lg]|=(E[i-1]<E[i])<<(i%lg);

    for(int b=0;b<sz;b++){
      int e=0,w=1,&x=T[b];
      for(int i=0;i<lg;i++){
	if((b>>i)&1) e++;
	else e--;
	if(e<w) e=w,x=i;
      }
    }

    int m=(n*2+lg-1)/lg;
    int h=1;
    while((1<<h)<m) h++;
    dat.assign(h,vector<int>(m,-1));
    ht.assign(m+1,0);
    for(int j=2;j<=m;j++) ht[j]=ht[j>>1]+1;
    
    for(int j=0;j<n*2;j++){
      if(dat[0][j/lg]<0) dat[0][j/lg]=j;
      dat[0][j/lg]=comp(dat[0][j/lg],j);
    }
    
    for(int i=1,p=1;i<h;i++,p<<=1)
      for(int j=0;j<m;j++)
        dat[i][j]=comp(dat[i-1][j],dat[i-1][min(j+p,m-1)]);
  }

  inline int cs(int a,int b){
    int l=b-a;
    return comp(dat[ht[l]][a],dat[ht[l]][b-(1<<ht[l])]);
  }

  inline int es(int i,int l,int r){
    int x=r-i*lg+1,y=l-i*lg;
    int b=(((B[i]|(ms<<x))>>y)|(ms<<(lg-y)))&ms;
    return l+T[b];
  }
  
  inline int ls(int i,int l){
    int k=l-i*lg;
    int b=((B[i]>>k)|(ms<<(lg-k)))&ms;
    return l+T[b];
  }

  inline int rs(int j,int r){
    int k=r-j*lg+1;
    int b=(B[j]|(ms<<k))&ms;
    return j*lg+T[b];
  }

  inline int rmq(int l,int r){
    int i=l/lg,j=r/lg;
    if(i==j) return es(i,l,r);
    if(i+1==j) return comp(ls(i,l),rs(j,r));
    return comp(ls(i,l),cs(i+1,j),rs(j,r));    
  }
  
  inline int lca(int l,int r){
    if(l==r) return l;
    if(D[l]>D[r]) swap(l,r);
    int x=D[l],y=D[r];
    int m=rmq(x,y);
    return m==x?l:A[m];
  }
};

struct RMQ{
  CartesianTree ct;
  LCA lca;
  vector<int> lcp;
  
  RMQ(Int n):ct(n+1),lca(n+1){}
  
  void build(vector<int> v){
    lcp=v;
    int r=ct.build(lcp);
    for(int i=0;i<(int)v.size();i++)
    if(~ct.P[i]) lca.add_edge(i,ct.P[i]);
    lca.build(r);
  };

  inline int query(Int a,Int b){
    if(a>b) swap(a,b);
    return lcp[lca.lca(a,b-1)];
  }
};


struct SuffixArray{
  string S;
  Int n,k;
  vector<Int> sa,lcp;  
  RMQ rmq;
  SuffixArray(string& S):S(S),n(S.length()),rmq(n){init();}
  void init(){
    S.push_back('$');
    build_sa();
    build_lcp();
    build_rmq();
  }
  void build_sa(){
    sa.clear();
    sa.resize(n+1,0);
    iota(sa.begin(),sa.end(),0);
    sort(sa.begin(),sa.end(),
	 [&](Int a,Int b){
	   if(S[a]==S[b]) return a>b;
	   return S[a]<S[b];
	 });
    vector<Int> c(n+1,0),r(n+1),cnt(n+1),s(n+1);
    for(Int i=0;i<=n;i++) r[i]=S[i];
    for(Int len=1;len<=n;len*=2){
      for(Int i=0;i<=n;i++){
	 c[sa[i]]=
	   i>0 &&
	   r[sa[i-1]]==r[sa[i]] &&
	   sa[i-1]+len<=n &&
	   r[sa[i-1]+len/2]==r[sa[i]+len/2] ?
	   c[sa[i-1]]:i;
      }
      iota(cnt.begin(),cnt.end(),0);
      copy(sa.begin(),sa.end(),r.begin());
      for(Int i=0;i<=n;i++){
	Int s1=r[i]-len;
	if(s1>=0) sa[cnt[c[s1]]++]=s1;
      }
      c.swap(r);
    }
  }
  
  bool lt_substr(string &T,Int si=0,Int ti=0){
    Int sn=S.size(),tn=T.size();
    while(si<sn&&ti<tn){
      if(S[si]<T[ti]) return 1;
      if(S[si]>T[ti]) return 0;
      si++;ti++;
    }
    return si>=sn&&ti<tn;
  }
  
  Int lower_bound(string& T){
    Int low=0,high=n+1;
    while(low+1<high){
      Int mid=(low+high)/2;
      if(lt_substr(T,sa[mid],0)) low=mid;
      else high=mid;
    }
    return high;
  }
  
  Int upper_bound(string& T){
    T.back()++;
    Int res=lower_bound(T);
    T.back()--;
    return res;
  }
  
  // O(|T|*log|S|)
  Int count(string& T){
    return upper_bound(T)-lower_bound(T);
  }
  
  void build_lcp(){
    lcp.clear();
    lcp.resize(n+1,0);
    vector<Int> r2(n+1);
    for(Int i=0;i<=n;i++) r2[sa[i]]=i;
    Int h=0;
    lcp[0]=0;
    for(Int i=0;i<n;i++){
      Int j=sa[r2[i]-1];
      if(h>0) h--;
      for(;j+h<n&&i+h<n;h++){
	if(S[j+h]!=S[i+h]) break;
      }
      lcp[r2[i]-1]=h;
    }
  }
  
  void build_rmq(){
    rmq.build(lcp);
  }
  
};

//INSERT ABOVE HERE
char buf[514514];
signed main(){
  scanf("%s",buf);
  string s(buf);
  Int n=s.size();
  
  {
    string t(s);
    t.erase(unique(t.begin(),t.end()),t.end());
    if(t.size()==1u){
      printf("%d\n",n);
      puts("1");
      return 0;
    }
  }
  
  vector<vector<Int> > v(n+1);
  for(Int i=1;i<=n;i++)
    for(Int j=i+i;j<=n;j+=i)
      v[j].emplace_back(i);

  SuffixArray sa(s);
  vector<Int> rev(n+1);
  for(Int i=0;i<=n;i++) rev[sa.sa[i]]=i;
  auto check=[&](Int l,Int r)->Int{    
    for(Int x:v[r-l])
      if(sa.rmq.query(rev[l],rev[l+x])>=r-l-x) return 0;
    return 1;
  };
  
  if(check(0,n)){
    puts("1");
    puts("1");
    return 0;
  }
  puts("2");
  
  Int ans=0;
  for(Int i=1;i<n;i++)
    ans+=check(0,i)&&check(i,n);

  printf("%d\n",ans);
  return 0;
}


Measured memory_bytes: 130180