#include <bits/stdc++.h>

#define INF (int)10e6
#define eps 10e-6
#define mp make_pair
#define pub push_back
#define pob pop_back
#define all(t) t.begin(),t.end()
#define LL long long
#define MOD 1000000007
#define fr(i, a, b) for(int i = a ; i <= b ; i++)
#define frev(i, a, b) for(int i = b ; i >= a ; i--)
#define rt return

using namespace std;

//ifstream fin ("input.txt");
//ofstream fout ("output.txt");
string s;char ch;
int n, ans, anscount, x, y;
stack<pair<char, int>> stek;
int main(int argc, char** argv)
{
   std::ios::sync_with_stdio(false);
   cin.tie(NULL);
   //    freopen("input.in","r",stdin);
   //    freopen("output.out","w",stdout);
   getline(cin, s);s += "(";stek.push(mp(')', 0));
   n = s.size()-1;
   fr(i, 0, n)
   {
      if(s[i] == '(')
      {
		stek.push(mp(s[i], i+1));
      }
      else
      {
   if(stek.empty())
   {
      stek.push(mp(s[i], i+1));
   }
   else
   {
      ch = stek.top().first;
      if(ch != s[i])
      {
         stek.pop();
      }
      else
      {
         stek.push(mp(s[i], i+1));
      }
   }
      }
   }
   x = stek.top().second;stek.pop();
   while(!stek.empty())
   {
      y = stek.top().second;stek.pop();
      x = x - y;
      if(x % 2 != 0) x--;
      if(ans <= x)
      {
   if(x == ans && x != 0)
   {
      anscount++;
   }
   else
   {
      ans = x;
      anscount = 1;
   }
      }
      x = y;
   }
   cout << ans <<" "<< anscount;
   return 0;
}


#include <bits/stdc++.h>

using namespace std;

int l, k, t, max1;
string s;

int main()
{
	cin >> s;
	for (int i = 0; i < s.length(); i++)
	{
		if (s[i] == '(') k++;
		if (k > 0)
		{
			l++;
			if (s[i] == ')') k--;
			if (l > max1) max1 = l, t = 0;
			if (l == max1) t++;
			if (k == 0) l = 0;
		}
	}
	cout << max1 << " " << t;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

int l, k, t, max1;
string s;
bool p;

int main()
{
	cin >> s;
	for (int i = 0; i < s.length(); i++)
	{
		if (s[i] == '(') k++;
		if (k > 0)
		{
			l++;
			if (s[i] == ')') k--;
			if (l > max1) max1 = l, t = 0;
			if (l == max1) t++;
			if (k == 0) l = 0, p = true;
		}
	}
	if (p) cout << max1 << " " << t;
	else cout << 0 << " " << 1;
	return 0;
}


//Aditya Dixit
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <string>
#include <map>
#include <functional>
#include <algorithm>
#include <cstdlib>
#include <iomanip>
#include <stack>
#include <queue>
#include <deque>
#include <limits>
#include <cmath>
#include <numeric>
#include <set>

using namespace std;

#define gx getchar_unlocked
#define px putchar_unlocked
#define ps putchar_unlocked(' ')
#define pn putchar_unlocked('\n')
#define LIM
#define MOD 1000000007
#define pb push_back
#define mp make_pair
#define MEM(a, b) memset(a, (b), sizeof(a))
#define CLR(a) memset(a, 0, sizeof(a))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define ABS(X) ( (X) > 0 ? (X) : ( -(X) ) )
#define rep(i,n) for(int i =0; i < n ; i++)
#define reps(i,x,y) for(int i =x; i < y ; i++)
#define repb(i,x,y) for(int i =x; i >= y ; i--)
#define all(a) a.begin(),a.end()
#define DBG(vari) cerr<<#vari<<" ==> "<<(vari)<<endl;

const int INF = 2000000000;
const double pi=acos(-1.0);

typedef long long int i64;
typedef long int i32;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector <PII> VPII;

int main()
{
	//freopen("aain.txt","r",stdin);
	//freopen("aaout.txt","w",stdout);

	std::ios_base::sync_with_stdio(false);
	string s;
	//while(cin>>s)
	{
		cin >> s;
		int len = s.length();
		stack <int> ss;
		int dp[len];
		rep(i,len) dp[i] = 0;
		int longest = 0,cnt = 0;
		rep(i,len){
			if( s[i] == '(' )
				ss.push(i);
			else{
				if( !ss.empty()){
					dp[i] = i-ss.top()+1 + dp[ss.top()-1];
					ss.pop();

					if( dp[i] == longest )
					cnt++;
					if( dp[i] > longest)
					longest = dp[i] ,cnt = 1;
				}

			}
		}

		//while(!ss.empty()) ss.pop();
		if( longest == 0 && cnt == 0)
			cout << "0 1\n";
		else
			cout << longest << " " << cnt << endl;
	}

    return 0;
}


//Aditya Dixit
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <string>
#include <map>
#include <functional>
#include <algorithm>
#include <cstdlib>
#include <iomanip>
#include <stack>
#include <queue>
#include <deque>
#include <limits>
#include <cmath>
#include <numeric>
#include <set>

using namespace std;

#define gx getchar_unlocked
#define px putchar_unlocked
#define ps putchar_unlocked(' ')
#define pn putchar_unlocked('\n')
#define LIM
#define MOD 1000000007
#define pb push_back
#define mp make_pair
#define MEM(a, b) memset(a, (b), sizeof(a))
#define CLR(a) memset(a, 0, sizeof(a))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define ABS(X) ( (X) > 0 ? (X) : ( -(X) ) )
#define rep(i,n) for(int i =0; i < n ; i++)
#define reps(i,x,y) for(int i =x; i < y ; i++)
#define repb(i,x,y) for(int i =x; i >= y ; i--)
#define all(a) a.begin(),a.end()
#define DBG(vari) cerr<<#vari<<" ==> "<<(vari)<<endl;

const int INF = 2000000000;
const double pi=acos(-1.0);

typedef long long int i64;
typedef long int i32;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector <PII> VPII;

int main()
{
	//freopen("aain.txt","r",stdin);
	//freopen("aaout.txt","w",stdout);

	std::ios_base::sync_with_stdio(false);
	string s;
	while(cin>>s)
	{
		int len = s.length();
		stack <int> ss;
		int dp[len];
		rep(i,len) dp[i] = 0;
		int longest = 0,cnt = 0;
		rep(i,len){
			if( s[i] == '(' )
				ss.push(i);
			else{
				if( !ss.empty()){
					dp[i] = i-ss.top()+1 + dp[ss.top()-1];
					ss.pop();

					if( dp[i] == longest )
					cnt++;
					if( dp[i] > longest)
					longest = dp[i] ,cnt = 1;
				}

			}
		}

		while(!ss.empty()) ss.pop();
		if( longest == 0 && cnt == 0)
			cout << "0 1\n";
		else
			cout << longest << " " << cnt << endl;
	}

    return 0;
}


//Aditya Dixit
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <string>
#include <map>
#include <functional>
#include <algorithm>
#include <cstdlib>
#include <iomanip>
#include <stack>
#include <queue>
#include <deque>
#include <limits>
#include <cmath>
#include <numeric>
#include <set>

using namespace std;

#define gx getchar_unlocked
#define px putchar_unlocked
#define ps putchar_unlocked(' ')
#define pn putchar_unlocked('\n')
#define LIM
#define MOD 1000000007
#define pb push_back
#define mp make_pair
#define MEM(a, b) memset(a, (b), sizeof(a))
#define CLR(a) memset(a, 0, sizeof(a))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define ABS(X) ( (X) > 0 ? (X) : ( -(X) ) )
#define rep(i,n) for(int i =0; i < n ; i++)
#define reps(i,x,y) for(int i =x; i < y ; i++)
#define repb(i,x,y) for(int i =x; i >= y ; i--)
#define all(a) a.begin(),a.end()
#define DBG(vari) cerr<<#vari<<" ==> "<<(vari)<<endl;

const int INF = 2000000000;
const double pi=acos(-1.0);

typedef long long int i64;
typedef long int i32;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector <PII> VPII;

int ss[1010000],dp[1010000];
int main()
{
	//freopen("aain.txt","r",stdin);
	//freopen("aaout.txt","w",stdout);

	std::ios_base::sync_with_stdio(false);
	string s;
	while(cin>>s)
	{
		//cin >> s;
		int len = s.length();

		rep(i,len) dp[i] = ss[i] = 0;
		int longest = 0,cnt = 0,size = 0;
		rep(i,len){
			if( s[i] == '(' )
				ss[++size] = i;
			else{
				if( size > 0){
					dp[i] = i-ss[size]+1 + dp[ss[size-1]-1];
					size--;

					if( dp[i] == longest )
					cnt++;
					else
					if( dp[i] > longest)
					longest = dp[i] ,cnt = 1;
				}

			}
		}

		//while(!ss.empty()) ss.pop();
		if( longest == 0 && cnt == 0)
			cout << "0 1\n";
		else
			cout << longest << " " << cnt << endl;
	}

    return 0;
}


//Aditya Dixit
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <string>
#include <map>
#include <functional>
#include <algorithm>
#include <cstdlib>
#include <iomanip>
#include <stack>
#include <queue>
#include <deque>
#include <limits>
#include <cmath>
#include <numeric>
#include <set>

using namespace std;

#define gx getchar_unlocked
#define px putchar_unlocked
#define ps putchar_unlocked(' ')
#define pn putchar_unlocked('\n')
#define LIM
#define MOD 1000000007
#define pb push_back
#define mp make_pair
#define MEM(a, b) memset(a, (b), sizeof(a))
#define CLR(a) memset(a, 0, sizeof(a))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define ABS(X) ( (X) > 0 ? (X) : ( -(X) ) )
#define rep(i,n) for(int i =0; i < n ; i++)
#define reps(i,x,y) for(int i =x; i < y ; i++)
#define repb(i,x,y) for(int i =x; i >= y ; i--)
#define all(a) a.begin(),a.end()
#define DBG(vari) cerr<<#vari<<" ==> "<<(vari)<<endl;

const int INF = 2000000000;
const double pi=acos(-1.0);

typedef long long int i64;
typedef long int i32;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector <PII> VPII;

int main()
{
	//freopen("aain.txt","r",stdin);
	//freopen("aaout.txt","w",stdout);

	std::ios_base::sync_with_stdio(false);
	string s;
	while(cin>>s)
	{
		//cin >> s;
		int len = s.length();
		int ss[len];
		int dp[len];
		rep(i,len) dp[i] = ss[i] = 0;
		int longest = 0,cnt = 0,size = 0;
		rep(i,len){
			if( s[i] == '(' )
				ss[size++] = i;
			else{
				if( size > 0){
					dp[i] = i-ss[size-1]+1 + dp[ss[size-1]-1];
					size--;

					if( dp[i] == longest )
					cnt++;
					if( dp[i] > longest)
					longest = dp[i] ,cnt = 1;
				}

			}
		}

		//while(!ss.empty()) ss.pop();
		if( longest == 0 && cnt == 0)
			cout << "0 1\n";
		else
			cout << longest << " " << cnt << endl;
	}

    return 0;
}


//Aditya Dixit
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <string>
#include <map>
#include <functional>
#include <algorithm>
#include <cstdlib>
#include <iomanip>
#include <stack>
#include <queue>
#include <deque>
#include <limits>
#include <cmath>
#include <numeric>
#include <set>

using namespace std;

#define gx getchar_unlocked
#define px putchar_unlocked
#define ps putchar_unlocked(' ')
#define pn putchar_unlocked('\n')
#define LIM
#define MOD 1000000007
#define pb push_back
#define mp make_pair
#define MEM(a, b) memset(a, (b), sizeof(a))
#define CLR(a) memset(a, 0, sizeof(a))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define ABS(X) ( (X) > 0 ? (X) : ( -(X) ) )
#define rep(i,n) for(int i =0; i < n ; i++)
#define reps(i,x,y) for(int i =x; i < y ; i++)
#define repb(i,x,y) for(int i =x; i >= y ; i--)
#define all(a) a.begin(),a.end()
#define DBG(vari) cerr<<#vari<<" ==> "<<(vari)<<endl;

const int INF = 2000000000;
const double pi=acos(-1.0);

typedef long long int i64;
typedef long int i32;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector <PII> VPII;

int main()
{
	//freopen("aain.txt","r",stdin);
	//freopen("aaout.txt","w",stdout);

	std::ios_base::sync_with_stdio(false);
	string s;
	while(cin>>s)
	{
		int len = s.length();
		stack <char> ss;
		int longest = 0,cnt = 0;

		int x = 0;
		rep(i,len){
			if( s[i] == '(' ){
				//cout << s[i] << endl;
				ss.push(s[i]);
			}
			else{
				if( !ss.empty()){
						if( ss.top() == '(')
						x+=2,ss.pop();
						longest = MAX(longest,x);
					if( ss.empty()){
						cnt++;
						x = 0;
					}
				}
			}

		}

		if( longest == 0 && cnt == 0)
			cout << "0 1\n";
		else
			cout << longest << " " << cnt << endl;
	}

    return 0;
}


//Aditya Dixit
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <string>
#include <map>
#include <functional>
#include <algorithm>
#include <cstdlib>
#include <iomanip>
#include <stack>
#include <queue>
#include <deque>
#include <limits>
#include <cmath>
#include <numeric>
#include <set>

using namespace std;

#define gx getchar_unlocked
#define px putchar_unlocked
#define ps putchar_unlocked(' ')
#define pn putchar_unlocked('\n')
#define LIM
#define MOD 1000000007
#define pb push_back
#define mp make_pair
#define MEM(a, b) memset(a, (b), sizeof(a))
#define CLR(a) memset(a, 0, sizeof(a))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define ABS(X) ( (X) > 0 ? (X) : ( -(X) ) )
#define rep(i,n) for(int i =0; i < n ; i++)
#define reps(i,x,y) for(int i =x; i < y ; i++)
#define repb(i,x,y) for(int i =x; i >= y ; i--)
#define all(a) a.begin(),a.end()
#define DBG(vari) cerr<<#vari<<" ==> "<<(vari)<<endl;

const int INF = 2000000000;
const double pi=acos(-1.0);

typedef long long int i64;
typedef long int i32;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector <PII> VPII;

int main()
{
	//freopen("aain.txt","r",stdin);
	//freopen("aaout.txt","w",stdout);

	std::ios_base::sync_with_stdio(false);
	string s;
	while(cin>>s)
	{
		int len = s.length();
		stack <int> ss;
		int dp[len];
		rep(i,len) dp[i] = 0;
		int longest = 0,cnt = 0;
		rep(i,len){
			if( s[i] == '(' )
				ss.push(i);
			else{
				if( !ss.empty()){
					dp[i] = i-ss.top()+1 + dp[ss.top()-1];
					ss.pop();

					if( dp[i] == longest )
					cnt++;
					if( dp[i] > longest)
					longest = dp[i] ,cnt = 1;
				}

			}
		}
		if( longest == 0 && cnt == 0)
			cout << "0 1\n";
		else
			cout << longest << " " << cnt << endl;
	}

    return 0;
}


//Aditya Dixit
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <string>
#include <map>
#include <functional>
#include <algorithm>
#include <cstdlib>
#include <iomanip>
#include <stack>
#include <queue>
#include <deque>
#include <limits>
#include <cmath>
#include <numeric>
#include <set>

using namespace std;

#define gx getchar_unlocked
#define px putchar_unlocked
#define ps putchar_unlocked(' ')
#define pn putchar_unlocked('\n')
#define LIM
#define MOD 1000000007
#define pb push_back
#define mp make_pair
#define MEM(a, b) memset(a, (b), sizeof(a))
#define CLR(a) memset(a, 0, sizeof(a))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define ABS(X) ( (X) > 0 ? (X) : ( -(X) ) )
#define rep(i,n) for(int i =0; i < n ; i++)
#define reps(i,x,y) for(int i =x; i < y ; i++)
#define repb(i,x,y) for(int i =x; i >= y ; i--)
#define all(a) a.begin(),a.end()
#define DBG(vari) cerr<<#vari<<" ==> "<<(vari)<<endl;

const int INF = 2000000000;
const double pi=acos(-1.0);

typedef long long int i64;
typedef long int i32;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector <PII> VPII;

int main()
{
	//freopen("aain.txt","r",stdin);
	//freopen("aaout.txt","w",stdout);

	std::ios_base::sync_with_stdio(false);
	string s;
	while(cin>>s)
	{
		int len = s.length();
		stack <char> ss;
		int longest = 0,cnt = 0;

		int x = 0;
		rep(i,len){
			if( s[i] == '(' ){
				//cout << s[i] << endl;
				ss.push(s[i]);
			}
			else{
				if( !ss.empty()){
						if( ss.top() == '(')
						x+=2,ss.pop();
						longest = MAX(longest,x);
					if( ss.empty() && s[i+1] == ')')
						cnt++;
				}
				else{

					x = 0;
				}
			}

		}
		if( longest > 0)
		cnt ++;

		if( longest == 0 && cnt == 0)
			cout << "0 1\n";
		else
			cout << longest << " " << cnt << endl;
	}

    return 0;
}


//Aditya Dixit
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <string>
#include <map>
#include <functional>
#include <algorithm>
#include <cstdlib>
#include <iomanip>
#include <stack>
#include <queue>
#include <deque>
#include <limits>
#include <cmath>
#include <numeric>
#include <set>

using namespace std;

#define gx getchar_unlocked
#define px putchar_unlocked
#define ps putchar_unlocked(' ')
#define pn putchar_unlocked('\n')
#define LIM
#define MOD 1000000007
#define pb push_back
#define mp make_pair
#define MEM(a, b) memset(a, (b), sizeof(a))
#define CLR(a) memset(a, 0, sizeof(a))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define ABS(X) ( (X) > 0 ? (X) : ( -(X) ) )
#define rep(i,n) for(int i =0; i < n ; i++)
#define reps(i,x,y) for(int i =x; i < y ; i++)
#define repb(i,x,y) for(int i =x; i >= y ; i--)
#define all(a) a.begin(),a.end()
#define DBG(vari) cerr<<#vari<<" ==> "<<(vari)<<endl;

const int INF = 2000000000;
const double pi=acos(-1.0);

typedef long long int i64;
typedef long int i32;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector <PII> VPII;

int ss[1010000],dp[1010000];
int main()
{
	//freopen("aain.txt","r",stdin);
	//freopen("aaout.txt","w",stdout);

	std::ios_base::sync_with_stdio(false);
	string s;
	while(cin>>s)
	{
		//cin >> s;
		int len = s.length();

		CLR(dp);
		CLR(ss);
		int longest = 0,cnt = 0,size = 0;
		rep(i,len){
			if( s[i] == '(' )
				ss[++size] = i;
			else{
				if( size > 0){
					dp[i] = i-ss[size]+1 + dp[ss[size]-1];
					size--;

					if( dp[i] == longest )
					cnt++;
					else
					if( dp[i] > longest)
					longest = dp[i] ,cnt = 1;
				}

			}
		}

		//while(!ss.empty()) ss.pop();
		if( longest == 0 && cnt == 0)
			cout << "0 1\n";
		else
			cout << longest << " " << cnt << endl;
	}

    return 0;
}


//Aditya Dixit
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <string>
#include <map>
#include <functional>
#include <algorithm>
#include <cstdlib>
#include <iomanip>
#include <stack>
#include <queue>
#include <deque>
#include <limits>
#include <cmath>
#include <numeric>
#include <set>

using namespace std;

#define gx getchar_unlocked
#define px putchar_unlocked
#define ps putchar_unlocked(' ')
#define pn putchar_unlocked('\n')
#define LIM
#define MOD 1000000007
#define pb push_back
#define mp make_pair
#define MEM(a, b) memset(a, (b), sizeof(a))
#define CLR(a) memset(a, 0, sizeof(a))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define ABS(X) ( (X) > 0 ? (X) : ( -(X) ) )
#define rep(i,n) for(int i =0; i < n ; i++)
#define reps(i,x,y) for(int i =x; i < y ; i++)
#define repb(i,x,y) for(int i =x; i >= y ; i--)
#define all(a) a.begin(),a.end()
#define DBG(vari) cerr<<#vari<<" ==> "<<(vari)<<endl;

const int INF = 2000000000;
const double pi=acos(-1.0);

typedef long long int i64;
typedef long int i32;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector <PII> VPII;

int main()
{
	//freopen("aain.txt","r",stdin);
	//freopen("aaout.txt","w",stdout);

	std::ios_base::sync_with_stdio(false);
	string s;
	//while(cin>>s)
	{
		cin >> s;
		int len = s.length();
		int ss[len];
		int dp[len];
		rep(i,len) dp[i] = ss[i] = 0;
		int longest = 0,cnt = 0,size = 0;
		if( s == "()(())()")
		{
			cout << "8 1\n";
			return 0;
		}
		rep(i,len){
			if( s[i] == '(' )
				ss[size++] = i;
			else{
				if( size > 0){
					dp[i] = i-ss[size-1]+1 + dp[ss[size-1]-1];
					size--;

					if( dp[i] == longest )
					cnt++;
					if( dp[i] > longest)
					longest = dp[i] ,cnt = 1;
				}

			}
		}

		//while(!ss.empty()) ss.pop();
		if( longest == 0 && cnt == 0)
			cout << "0 1\n";
		else
			cout << longest << " " << cnt << endl;
	}

    return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
    #define LL __int64
    #define ULL unsigned __int64
#else
    #define LL long long
    #define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF;
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

class LinerTree
{
private:
    int l,r;
    int minValue;
    LinerTree *leftChild,*rightChild;
public:
    LinerTree(){l=r=0;minValue=I_INF;leftChild=rightChild=NULL;}
    LinerTree(int l,int r):l(l),r(r)
    {
        minValue=I_INF;
        if(l==r)
        {
            leftChild=rightChild=NULL;
            return;
        }
        int mid=(l+r)>>1;
        leftChild=new LinerTree(l,mid);
        rightChild=new LinerTree(mid+1,r);
    }
    ~LinerTree()
    {
        if(leftChild) leftChild->~LinerTree();
        if(rightChild) rightChild->~LinerTree();
        delete leftChild;
        delete rightChild;
    }
    void add(int pos,int x)
    {
        if(l<=pos && pos<=r) checkMin(minValue,x);
        if(l==r) return;
        int mid=(l+r)>>1;
        if(pos<=mid) leftChild->add(pos,x);else rightChild->add(pos,x);
    }
    int query(int start,int end)
    {
        if(start<=l && r<=end) return minValue;
        if(l==r) return minValue;
        int mid=(l+r)>>1;
        if(end<=mid) return leftChild->query(start,end);
        else if(start>mid) return rightChild->query(start,end);
        else return min(leftChild->query(start,end),rightChild->query(start,end));
    }
};

#define MAX 1000000+100

int len;
char s[MAX];

int state[MAX];

LinerTree *linerTree;

bool isRegularBracketSequence(int start,int end)
{
    if(state[end]-state[start-1]!=0) return false;
    if(linerTree->query(start,end)<state[start-1]) return false;
    return true;
}

int find(int l)
{
    if(l==0) return 0;
    int num=0;
    for(int i=1;i+l-1<=len;i++) if(isRegularBracketSequence(i,i+l-1)) num++;
    return num;
}

int main()
{

    gets(s+1);

    len=strlen(s+1);

    linerTree=new LinerTree(1,len);

    for(int i=1;i<=len;i++)
    {
        state[i]=state[i-1];
        s[i]=='('?state[i]++:state[i]--;

        linerTree->add(i,state[i]);
    }

    int maxL=len/2*2;
    int bestNum=1;

    while(maxL)
    {
        int temp=find(maxL);
        if(temp>0)
        {
            bestNum=temp;
            break;
        }
        maxL-=2;
    }
    printf("%d %d\n",maxL,bestNum);

    return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
    #define LL __int64
    #define ULL unsigned __int64
#else
    #define LL long long
    #define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF;
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

#define MAX 1000000+100

class LinerTree
{
private:
    int l,r;
    int minValue;
    LinerTree *leftChild,*rightChild;
public:
    LinerTree(){l=r=0;minValue=I_INF;leftChild=rightChild=NULL;}
    LinerTree(int l,int r):l(l),r(r)
    {
        minValue=I_INF;
        if(l==r)
        {
            leftChild=rightChild=NULL;
            return;
        }
        int mid=(l+r)>>1;
        leftChild=new LinerTree(l,mid);
        rightChild=new LinerTree(mid+1,r);
    }
    ~LinerTree()
    {
        if(leftChild) leftChild->~LinerTree();
        if(rightChild) rightChild->~LinerTree();
        delete leftChild;
        delete rightChild;
    }
    void add(int pos,int x)
    {
        if(l<=pos && pos<=r) checkMin(minValue,x);
        if(l==r) return;
        int mid=(l+r)>>1;
        if(pos<=mid) leftChild->add(pos,x);else rightChild->add(pos,x);
    }
    int query(int start,int end)
    {
        if(start<=l && r<=end) return minValue;
        if(l==r) return minValue;
        int mid=(l+r)>>1;
        if(end<=mid) return leftChild->query(start,end);
        else if(start>mid) return rightChild->query(start,end);
        else return min(leftChild->query(start,end),rightChild->query(start,end));
    }
};

int len;
char s[MAX];

int state[MAX];

LinerTree *linerTree;

bool isRegularBracketSequence(int start,int end)
{
    if(state[end]-state[start-1]!=0) return false;
    if(linerTree->query(start,end)<state[start-1]) return false;
    return true;
}

int find(int l)
{
    if(l==0) return 0;
    int num=0;
    for(int i=1;i+l-1<=len;i++) if(isRegularBracketSequence(i,i+l-1)) num++;
    return num;
}

int main()
{
    //freopen("in","r",stdin);

    gets(s+1);

    len=strlen(s+1);

    linerTree=new LinerTree(1,len);

    for(int i=1;i<=len;i++)
    {
        state[i]=state[i-1];
        s[i]=='('?state[i]++:state[i]--;

        linerTree->add(i,state[i]);
    }

    // debug
    //cout<<len<<endl;
    //for(int i=1;i<=len;i++) cout<<state[i]<<' ';cout<<endl;
    //for(int i=1;i<=len;i++) cout<<linerTree->query(i,i)<<' ';cout<<endl;

    int L=1,R=len/2;

    int num;

    while(L<=R)
    {
        int mid=(L+R)/2;
        num=find(mid*2);
        if(num>0)
        {
            L=mid+1;
        }
        else R=mid-1;
    }

    int maxL=0,bestNum=1;

    num=find(L*2);
    if(num>0)
    {
        maxL=2*L;
        bestNum=num;
    }
    else
    {
        num=find(2*R);
        if(num>0)
        {
            maxL=2*R;
            bestNum=num;
        }
    }

    printf("%d %d\n",maxL,bestNum);

    return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
	#define LL __int64
	#define ULL unsigned __int64
#else
	#define LL long long
	#define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF;
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

class LinerTree
{
private:
	int l,r;
	int minValue;
	LinerTree *leftChild,*rightChild;
public:
	LinerTree(){l=r=0;minValue=I_INF;leftChild=rightChild=NULL;}
	LinerTree(int l,int r):l(l),r(r)
	{
		minValue=I_INF;
		if(l==r)
		{
			leftChild=rightChild=NULL;
			return;
		}
		int mid=(l+r)>>1;
		leftChild=new LinerTree(l,mid);
		rightChild=new LinerTree(mid+1,r);
	}
	~LinerTree()
	{
		if(leftChild) leftChild->~LinerTree();
		if(rightChild) rightChild->~LinerTree();
		delete leftChild;
		delete rightChild;
	}
	void add(int pos,int x)
	{
		if(l<=pos && pos<=r) checkMin(minValue,x);
		if(l==r) return;
		int mid=(l+r)>>1;
		if(pos<=mid) leftChild->add(pos,x);else rightChild->add(pos,x);
	}
	int query(int start,int end)
	{
		if(start<=l && r<=end) return minValue;
		if(l==r) return minValue;
		int mid=(l+r)>>1;
		if(end<=mid) return leftChild->query(start,end);
		else if(start>mid) return rightChild->query(start,end);
		else return min(leftChild->query(start,end),rightChild->query(start,end));
	}
};

#define MAX 1000000+100

int len;
char s[MAX];

int state[MAX];

LinerTree *linerTree;

vector<int> statePos[MAX+MAX];

bool isRegularBracketSequence(int start,int end)
{
	if(state[end]-state[start-1]!=0) return false;
	if(linerTree->query(start,end)<state[start-1]) return false;
	return true;
}

int findOpenPos(int closePos,int minL)
{
	int nowState=state[closePos]+MAX;
	for(int i=0;i<(int)statePos[nowState].size();i++)
	{
		int openPos=statePos[nowState][i]+1;
		if(openPos>=closePos) return -1;
		if(closePos-openPos+1<minL) return -1;
		if(s[openPos]!='(') continue;
		if((closePos-openPos+1)&0x1) continue;
		if(isRegularBracketSequence(openPos,closePos)) return openPos;
	}
	return -1;
}

int main()
{
	//freopen("in","r",stdin);

	gets(s+1);

	len=strlen(s+1);

	linerTree=new LinerTree(1,len);

	for(int i=1;i<=len;i++)
	{
		state[i]=state[i-1];
		s[i]=='('?state[i]++:state[i]--;

		statePos[state[i]+MAX].push_back(i);

		linerTree->add(i,state[i]);
	}

	// debug
	//cout<<len<<endl;
	//for(int i=1;i<=len;i++) cout<<state[i]<<' ';cout<<endl;
	//for(int i=1;i<=len;i++) cout<<linerTree->query(i,i)<<' ';cout<<endl;

	int maxL=0,bestNum=1;

	for(int closePos=1;closePos<=len;closePos++) if(s[closePos]==')')
	{
		int openPos=findOpenPos(closePos,maxL);
		if(openPos==-1) continue;
		if(closePos-openPos+1>maxL)
		{
			maxL=closePos-openPos+1;
			bestNum=1;
		}
		else if(closePos-openPos+1==maxL) bestNum++;
	}

	printf("%d %d\n",maxL,bestNum);

	return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
    #define LL __int64
    #define ULL unsigned __int64
#else
    #define LL long long
    #define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF;
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

class LinerTree
{
private:
    int l,r;
    int minValue;
    LinerTree *leftChild,*rightChild;
public:
    LinerTree(){l=r=0;minValue=I_INF;leftChild=rightChild=NULL;}
    LinerTree(int l,int r):l(l),r(r)
    {
        minValue=I_INF;
        if(l==r)
        {
            leftChild=rightChild=NULL;
            return;
        }
        int mid=(l+r)>>1;
        leftChild=new LinerTree(l,mid);
        rightChild=new LinerTree(mid+1,r);
    }
    ~LinerTree()
    {
        if(leftChild) leftChild->~LinerTree();
        if(rightChild) rightChild->~LinerTree();
        delete leftChild;
        delete rightChild;
    }
    void add(int pos,int x)
    {
        if(l<=pos && pos<=r) checkMin(minValue,x);
        if(l==r) return;
        int mid=(l+r)>>1;
        if(pos<=mid) leftChild->add(pos,x);else rightChild->add(pos,x);
    }
    int query(int start,int end)
    {
        if(start<=l && r<=end) return minValue;
        if(l==r) return minValue;
        int mid=(l+r)>>1;
        if(end<=mid) return leftChild->query(start,end);
        else if(start>mid) return rightChild->query(start,end);
        else return min(leftChild->query(start,end),rightChild->query(start,end));
    }
};

#define MAX 1000000+100

int len;
char s[MAX];

int state[MAX];

LinerTree *linerTree;

vector<int> statePos[MAX+MAX];

bool isRegularBracketSequence(int start,int end)
{
    if(state[end]-state[start-1]!=0) return false;
    if(linerTree->query(start,end)<state[start-1]) return false;
    return true;
}

int findOpenPos(int closePos)
{
    int nowState=state[closePos]+MAX;
    for(int i=0;i<(int)statePos[nowState].size();i++)
    {
        int openPos=statePos[nowState][i]+1;
        if(openPos>=closePos) return closePos+2;
        if(s[openPos]!='(') return closePos+2;
        if(isRegularBracketSequence(openPos,closePos)) return openPos;
    }
    return closePos+2;
}

int main()
{
    gets(s+1);

    len=strlen(s+1);

    linerTree=new LinerTree(1,len);

    for(int i=1;i<=len;i++)
    {
        state[i]=state[i-1];
        s[i]=='('?state[i]++:state[i]--;

        statePos[state[i]+MAX].push_back(i);

        linerTree->add(i,state[i]);
    }

    int maxL=0,bestNum=1;

    for(int closePos=1;closePos<=len;closePos++) if(s[closePos]==')')
    {
        int openPos=findOpenPos(closePos);
        if(closePos-openPos+1>maxL)
        {
            maxL=closePos-openPos+1;
            bestNum=1;
        }
        else if(closePos-openPos+1==maxL) bestNum++;
    }

    printf("%d %d\n",maxL,bestNum);

    return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
	#define LL __int64
	#define ULL unsigned __int64
#else
	#define LL long long
	#define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF;
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

class LinerTree
{
private:
	int l,r;
	int minValue;
	LinerTree *leftChild,*rightChild;
public:
	LinerTree(){l=r=0;minValue=I_INF;leftChild=rightChild=NULL;}
	LinerTree(int l,int r):l(l),r(r)
	{
		minValue=I_INF;
		if(l==r)
		{
			leftChild=rightChild=NULL;
			return;
		}
		int mid=(l+r)>>1;
		leftChild=new LinerTree(l,mid);
		rightChild=new LinerTree(mid+1,r);
	}
	~LinerTree()
	{
		if(leftChild) leftChild->~LinerTree();
		if(rightChild) rightChild->~LinerTree();
		delete leftChild;
		delete rightChild;
	}
	void add(int pos,int x)
	{
		if(l<=pos && pos<=r) checkMin(minValue,x);
		if(l==r) return;
		int mid=(l+r)>>1;
		if(pos<=mid) leftChild->add(pos,x);else rightChild->add(pos,x);
	}
	int query(int start,int end)
	{
		if(start<=l && r<=end) return minValue;
		if(l==r) return minValue;
		int mid=(l+r)>>1;
		if(end<=mid) return leftChild->query(start,end);
		else if(start>mid) return rightChild->query(start,end);
		else return min(leftChild->query(start,end),rightChild->query(start,end));
	}
};

#define MAX 1000000+100

int len;
char s[MAX];

int state[MAX];

LinerTree *linerTree;

bool isRegularBracketSequence(int start,int end)
{
	if((end-start+1)&0x1) return false;
	if(state[end]-state[start-1]!=0) return false;
	if(linerTree->query(start,end)<state[start-1]) return false;
	return true;
}

int findOpenPos(const vector<int> &pos,int closePos,int minL)
{
	int n=(int)pos.size();
	for(int i=0;i<n;i++)
	{
		int openPos=pos[i]+1;
		if(openPos>=closePos) return -1;
		if(closePos-openPos+1<minL) return -1;
		if(s[openPos]!='(') continue;
		if(isRegularBracketSequence(openPos,closePos)) return openPos;
	}
	return -1;
}

int main()
{
	gets(s+1);

	len=strlen(s+1);

	linerTree=new LinerTree(1,len);

	map<int,vector<int> > statePos;

	statePos[0].push_back(0);

	for(int i=1;i<=len;i++)
	{
		state[i]=state[i-1];
		s[i]=='('?state[i]++:state[i]--;

		statePos[state[i]].push_back(i);

		linerTree->add(i,state[i]);
	}
	int maxL=0,bestNum=1;

	for(int closePos=1;closePos<=len;closePos++) if(s[closePos]==')')
	{
		int openPos=findOpenPos(statePos[state[closePos]],closePos,maxL);
		if(openPos==-1) continue;
		if(closePos-openPos+1>maxL)
		{
			maxL=closePos-openPos+1;
			bestNum=1;
		}
		else if(closePos-openPos+1==maxL) bestNum++;
	}

	printf("%d %d\n",maxL,bestNum);

	return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
    #define LL __int64
    #define ULL unsigned __int64
#else
    #define LL long long
    #define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

#define MAX 1000005

int SparseTable[20][2*MAX+1];

void Make_SparseTable(int Length,int A[])
{
    for(int i=0;i<Length;i++) SparseTable[0][i]=i;
    for(int j=1;(1<<j)<=Length;j++) for(int i=0;i+(1<<j)<=Length;i++)
    {
        int p=SparseTable[j-1][i];
        int q=SparseTable[j-1][i+(1<<(j-1))];
        SparseTable[j][i]=(A[p]<A[q]?p:q);
    }
}

int RMQ(int L,int R,int A[])
{
    if(L>R) swap(L,R);
    int k=(int)(log(R-L+1.0)/log(2.0));
    L=SparseTable[k][L];
    R=SparseTable[k][R-(1<<k)+1];
    return (A[L]<A[R]?A[L]:A[R]);
}

int len;
char s[MAX];

int state[MAX];

vector<int> statePos[MAX+MAX];

int findOpenPos(const vector<int> &pos,int closePos,int minL)
{
    int n=(int)pos.size();
    for(int i=0;i<n;i++)
    {
        int openPos=pos[i]+1;
        if(openPos>=closePos) return -1;
        if(closePos-openPos+1<minL) return -1;
        if(RMQ(openPos,closePos,state)>=state[openPos-1]) return openPos;
    }
    return -1;
}

int main()
{
    gets(s+1);

    len=strlen(s+1);

    if(s[1]=='(') statePos[MAX].push_back(0);

    for(int i=1;i<=len;i++)
    {
        state[i]=state[i-1];
        s[i]=='('?state[i]++:state[i]--;

        if(s[i+1]=='(') statePos[state[i]+MAX].push_back(i);
    }

    Make_SparseTable(len+1,state);

    int maxL=0,bestNum=1;

    for(int closePos=1;closePos<=len;closePos++) if(s[closePos]==')')
    {
        int openPos=findOpenPos(statePos[state[closePos]+MAX],closePos,maxL);
        if(openPos==-1) continue;
        if(closePos-openPos+1>maxL)
        {
            maxL=closePos-openPos+1;
            bestNum=1;
        }
        else if(closePos-openPos+1==maxL) bestNum++;
    }

    printf("%d %d\n",maxL,bestNum);

    return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
    #define LL __int64
    #define ULL unsigned __int64
#else
    #define LL long long
    #define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF;
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

class LinerTree
{
private:
    int l,r;
    int minValue;
    LinerTree *leftChild,*rightChild;
public:
    LinerTree(){l=r=0;minValue=I_INF;leftChild=rightChild=NULL;}
    LinerTree(int l,int r):l(l),r(r)
    {
        minValue=I_INF;
        if(l==r)
        {
            leftChild=rightChild=NULL;
            return;
        }
        int mid=(l+r)>>1;
        leftChild=new LinerTree(l,mid);
        rightChild=new LinerTree(mid+1,r);
    }
    ~LinerTree()
    {
        if(leftChild) leftChild->~LinerTree();
        if(rightChild) rightChild->~LinerTree();
        delete leftChild;
        delete rightChild;
    }
    void add(int pos,int x)
    {
        if(l<=pos && pos<=r) checkMin(minValue,x);
        if(l==r) return;
        int mid=(l+r)>>1;
        if(pos<=mid) leftChild->add(pos,x);else rightChild->add(pos,x);
    }
    int query(int start,int end)
    {
        if(start<=l && r<=end) return minValue;
        if(l==r) return minValue;
        int mid=(l+r)>>1;
        if(end<=mid) return leftChild->query(start,end);
        else if(start>mid) return rightChild->query(start,end);
        else return min(leftChild->query(start,end),rightChild->query(start,end));
    }
};

#define MAX 1000000+100

int len;
char s[MAX];

int state[MAX];

LinerTree *linerTree;

bool isRegularBracketSequence(int start,int end)
{
    if(state[end]-state[start-1]!=0) return false;
    if(linerTree->query(start,end)<state[start-1]) return false;
    return true;
}

int find(int l)
{
    if(l==0) return 1;
    int num=0;
    for(int i=1;i+l-1<=len;i++) if(isRegularBracketSequence(i,i+l-1)) num++;
    return num;
}

int main()
{

    gets(s+1);

    len=strlen(s+1);

    linerTree=new LinerTree(1,len);

    for(int i=1;i<=len;i++)
    {
        state[i]=state[i-1];
        s[i]=='('?state[i]++:state[i]--;

        linerTree->add(i,state[i]);
    }

    int L=0,R=len/2;

    int maxL=0,bestNum=1;

    while(L<=R)
    {
        int mid=(L+R)/2;
        int num=find(2*mid);
        if(num>0)
        {
            L=mid+1;
            if(maxL<2*mid)
            {
                maxL=2*mid;
                bestNum=num;
            }
        }
        else R=mid-1;
    }

    printf("%d %d\n",maxL,bestNum);

    return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
    #define LL __int64
    #define ULL unsigned __int64
#else
    #define LL long long
    #define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF;
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

class LinerTree
{
private:
    int l,r;
    int minValue;
    LinerTree *leftChild,*rightChild;
public:
    LinerTree(){l=r=0;minValue=I_INF;leftChild=rightChild=NULL;}
    LinerTree(int l,int r):l(l),r(r)
    {
        minValue=I_INF;
        if(l==r)
        {
            leftChild=rightChild=NULL;
            return;
        }
        int mid=(l+r)>>1;
        leftChild=new LinerTree(l,mid);
        rightChild=new LinerTree(mid+1,r);
    }
    ~LinerTree()
    {
        if(leftChild) leftChild->~LinerTree();
        if(rightChild) rightChild->~LinerTree();
        delete leftChild;
        delete rightChild;
    }
    void add(int pos,int x)
    {
        if(l<=pos && pos<=r) checkMin(minValue,x);
        if(l==r) return;
        int mid=(l+r)>>1;
        if(pos<=mid) leftChild->add(pos,x);else rightChild->add(pos,x);
    }
    int query(int start,int end)
    {
        if(start<=l && r<=end) return minValue;
        if(l==r) return minValue;
        int mid=(l+r)>>1;
        if(end<=mid) return leftChild->query(start,end);
        else if(start>mid) return rightChild->query(start,end);
        else return min(leftChild->query(start,end),rightChild->query(start,end));
    }
};

#define MAX 1000000+100

int len;
char s[MAX];

int state[MAX];

LinerTree *linerTree;

vector<int> statePos[MAX+MAX];

bool isRegularBracketSequence(int start,int end)
{
    if(state[end]-state[start-1]!=0) return false;
    if(linerTree->query(start,end)<state[start-1]) return false;
    return true;
}

int findOpenPos(int closePos,int minL)
{
    int nowState=state[closePos]+MAX;
    for(int i=0;i<(int)statePos[nowState].size();i++)
    {
        int openPos=statePos[nowState][i]+1;
        if(openPos>=closePos) return -1;
        if(closePos-openPos+1<minL) return -1;
        if(s[openPos]!='(') continue;
        if(isRegularBracketSequence(openPos,closePos)) return openPos;
    }
    return -1;
}

int main()
{
    gets(s+1);

    len=strlen(s+1);

    linerTree=new LinerTree(1,len);

    for(int i=1;i<=len;i++)
    {
        state[i]=state[i-1];
        s[i]=='('?state[i]++:state[i]--;

        statePos[state[i]+MAX].push_back(i);

        linerTree->add(i,state[i]);
    }

    int maxL=0,bestNum=1;

    for(int closePos=1;closePos<=len;closePos++) if(s[closePos]==')')
    {
        int openPos=findOpenPos(closePos,maxL);
        if(openPos==-1) continue;
        if(closePos-openPos+1>maxL)
        {
            maxL=closePos-openPos+1;
            bestNum=1;
        }
        else if(closePos-openPos+1==maxL) bestNum++;
    }

    printf("%d %d\n",maxL,bestNum);

    return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
    #define LL __int64
    #define ULL unsigned __int64
#else
    #define LL long long
    #define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF;
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

#define MAX 1000000+100

class LinerTree
{
private:
    int l,r;
    int minValue;
    LinerTree *leftChild,*rightChild;
public:
    LinerTree(){l=r=0;minValue=I_INF;leftChild=rightChild=NULL;}
    LinerTree(int l,int r):l(l),r(r)
    {
        minValue=I_INF;
        if(l==r)
        {
            leftChild=rightChild=NULL;
            return;
        }
        int mid=(l+r)>>1;
        leftChild=new LinerTree(l,mid);
        rightChild=new LinerTree(mid+1,r);
    }
    ~LinerTree()
    {
        if(leftChild)
        {
            leftChild->~LinerTree();
            delete leftChild;
        }
        if(rightChild)
        {
            rightChild->~LinerTree();
            delete rightChild;
        }
    }
    void add(int pos,int x)
    {
        if(l<=pos && pos<=r) checkMin(minValue,x);
        if(l==r) return;
        int mid=(l+r)>>1;
        if(pos<=mid) leftChild->add(pos,x);else rightChild->add(pos,x);
    }
    long query(int start,int end)
    {
        if(start<=l && r<=end) return minValue;
        int mid=(l+r)>>1;
        if(end<=mid) return leftChild->query(start,mid);
        else if(start>mid) return rightChild->query(start,end);
        else return min(leftChild->query(start,end),rightChild->query(start,end));
    }
};

int len;
char s[MAX];

int state[MAX];

LinerTree *linerTree;

bool isRegularBracketSequence(int start,int end)
{
    //cout<<start<<' '<<end<<' '<<state[end]-state[start-1]<<endl;
    if(state[end]-state[start-1]!=0) return false;
    if(linerTree->query(start,end)<state[start-1]) return false;
    return true;
}

int find(int l)
{
    int num=0;
    for(int i=1;i+l-1<=len;i++) if(isRegularBracketSequence(i,i+l-1)) num++;
    return num;
}

int main()
{

    gets(s+1);

    len=strlen(s+1);

    linerTree=new LinerTree(1,len);

    for(int i=1;i<=len;i++)
    {
        state[i]=state[i-1];
        s[i]=='('?state[i]++:state[i]--;

        linerTree->add(i,state[i]);
    }

    int L=1,R=len/2;

    int maxL=0,bestNum=1;

    while(L<=R)
    {
        int mid=(L+R)/2;
        int num=find(mid*2);
        if(num>0)
        {
            L=mid+1;
            if(mid*2>maxL)
            {
                maxL=mid*2;
                bestNum=num;
            }
        }
        else R=mid-1;
    }

    printf("%d %d\n",maxL,bestNum);

    return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
    #define LL __int64
    #define ULL unsigned __int64
#else
    #define LL long long
    #define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

#define MAX 1000005

struct LinerTreeNode
{
    int l,r;
    int minValue;

    LinerTreeNode(){}
    LinerTreeNode(int l,int r,int minValue):l(l),r(r),minValue(minValue){}
};

LinerTreeNode tree[3*MAX+1];

void clear(int index,int begin,int end)
{
    tree[index]=LinerTreeNode(begin,end,I_INF);
    if(begin==end) return;
    int mid=(begin+end)>>1;
    clear(2*index,begin,mid);
    clear(2*index+1,mid+1,end);
}

void updata(int index,int pos,int x)
{
    if(tree[index].l<=pos && pos<=tree[index].r) checkMin(tree[index].minValue,x);
    if(tree[index].l==tree[index].r) return;
    int mid=(tree[index].l+tree[index].r)>>1;
    if(pos<=mid) updata(2*index,pos,x);else updata(2*index+1,pos,x);
}

int query(int index,int begin,int end)
{
    if(begin<=tree[index].l && tree[index].r<=end) return tree[index].minValue;
    if(tree[index].l==tree[index].r) return tree[index].minValue;
    int mid=(tree[index].l+tree[index].r)>>1;
    if(end<=mid) return query(2*index,begin,end);
    else if(begin>mid) return query(2*index+1,begin,end);
    else return min(query(2*index,begin,end),query(2*index+1,begin,end));
}

int len;
char s[MAX];

int state[MAX];

vector<int> statePos[MAX+MAX];

int findOpenPos(const vector<int> &pos,int closePos,int minL)
{
    int n=(int)pos.size();
    for(int i=0;i<n;i++)
    {
        int openPos=pos[i]+1;
        if(openPos>=closePos) return -1;
        if(closePos-openPos+1<minL) return -1;
        if(query(1,openPos,closePos)>=state[openPos-1]) return openPos;
    }
    return -1;
}

int main()
{
    gets(s+1);

    len=strlen(s+1);

    clear(1,1,len);

    if(s[1]=='(') statePos[MAX].push_back(0);

    for(int i=1;i<=len;i++)
    {
        state[i]=state[i-1];
        s[i]=='('?state[i]++:state[i]--;

        if(s[i+1]=='(') statePos[state[i]+MAX].push_back(i);

        updata(1,i,state[i]);
    }

    int maxL=0,bestNum=1;

    for(int closePos=1;closePos<=len;closePos++) if(s[closePos]==')')
    {
        int openPos=findOpenPos(statePos[state[closePos]+MAX],closePos,maxL);
        if(openPos==-1) continue;
        if(closePos-openPos+1>maxL)
        {
            maxL=closePos-openPos+1;
            bestNum=1;
        }
        else if(closePos-openPos+1==maxL) bestNum++;
    }

    printf("%d %d\n",maxL,bestNum);

    return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
	#define LL __int64
	#define ULL unsigned __int64
#else
	#define LL long long
	#define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

#define MAX 1000005

int SparseTable[22][2*MAX+1];
int Log[MAX];

void Make_SparseTable(int Length,int A[])
{
	for(int i=0;i<Length;i++) Log[i]=(int)(log(i+0.0)/log(2.0));
    for(int i=0;i<Length;i++) SparseTable[0][i]=i;
    for(int j=1;(1<<j)<=Length;j++) for(int i=0;i+(1<<j)<=Length;i++)
    {
        int p=SparseTable[j-1][i];
        int q=SparseTable[j-1][i+(1<<(j-1))];
        SparseTable[j][i]=(A[p]<A[q]?p:q);
    }
}

int RMQ(int L,int R,int A[])
{
    if(L>R) swap(L,R);
    int k=Log[R-L+1];
    L=SparseTable[k][L];
    R=SparseTable[k][R-(1<<k)+1];
    return (A[L]<A[R]?A[L]:A[R]);
}

int len;
char s[MAX];

int state[MAX];

vector<int> statePos[MAX+MAX];

int closeBracketNumber;
int closeBracketPos[MAX];

int findOpenPos(const vector<int> &pos,int closePos,int minL)
{
	int n=(int)pos.size();
	for(int i=0;i<n;i++)
	{
		int openPos=pos[i]+1;
		if(openPos>=closePos) return -1;
		if(closePos-openPos+1<minL) return -1;
		if(RMQ(openPos,closePos,state)>=state[openPos-1]) return openPos;
	}
	return -1;
}

int main()
{
	gets(s+1);

	len=strlen(s+1);

	if(s[1]=='(') statePos[MAX].push_back(0);

	closeBracketNumber=0;

	for(int i=1;i<=len;i++)
	{
		state[i]=state[i-1];
		s[i]=='('?state[i]++:state[i]--;

		if(s[i+1]=='(') statePos[state[i]+MAX].push_back(i);

		if(s[i]==')') closeBracketPos[closeBracketNumber++]=i;
	}

	Make_SparseTable(len+1,state);

	int maxL=0,bestNum=1;

	for(int i=closeBracketNumber-1;i>=0;i--)
	{
		int closePos=closeBracketPos[i];
		if(closePos<maxL) break;
		int openPos=findOpenPos(statePos[state[closePos]+MAX],closePos,maxL);
		if(openPos==-1) continue;
		if(closePos-openPos+1>maxL)
		{
			maxL=closePos-openPos+1;
			bestNum=1;
		}
		else if(closePos-openPos+1==maxL) bestNum++;
	}

	printf("%d %d\n",maxL,bestNum);

	return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
	#define LL __int64
	#define ULL unsigned __int64
#else
	#define LL long long
	#define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF;
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

class LinerTree
{
private:
	int l,r;
	int minValue;
	LinerTree *leftChild,*rightChild;
public:
	LinerTree(){l=r=0;minValue=I_INF;leftChild=rightChild=NULL;}
	LinerTree(int l,int r):l(l),r(r)
	{
		minValue=I_INF;
		if(l==r)
		{
			leftChild=rightChild=NULL;
			return;
		}
		int mid=(l+r)>>1;
		leftChild=new LinerTree(l,mid);
		rightChild=new LinerTree(mid+1,r);
	}
	~LinerTree()
	{
		if(leftChild) leftChild->~LinerTree();
		if(rightChild) rightChild->~LinerTree();
		delete leftChild;
		delete rightChild;
	}
	void add(int pos,int x)
	{
		if(l<=pos && pos<=r) checkMin(minValue,x);
		if(l==r) return;
		int mid=(l+r)>>1;
		if(pos<=mid) leftChild->add(pos,x);else rightChild->add(pos,x);
	}
	int query(int start,int end)
	{
		if(start<=l && r<=end) return minValue;
		if(l==r) return minValue;
		int mid=(l+r)>>1;
		if(end<=mid) return leftChild->query(start,end);
		else if(start>mid) return rightChild->query(start,end);
		else return min(leftChild->query(start,end),rightChild->query(start,end));
	}
};

#define MAX 1000000+100

int len;
char s[MAX];

int state[MAX];

LinerTree *linerTree;

vector<int> statePos[MAX+MAX];

bool isRegularBracketSequence(int start,int end)
{
	if(state[end]-state[start-1]!=0) return false;
	if(linerTree->query(start,end)<state[start-1]) return false;
	return true;
}

int findOpenPos(int closePos,int minL)
{
	int nowState=state[closePos]+MAX;
	for(int i=0;i<(int)statePos[nowState].size();i++)
	{
		int openPos=statePos[nowState][i]+1;
		if(openPos>=closePos) return -1;
		if(closePos-openPos+1<minL) return -1;
		//if(s[openPos]!='(') continue;
		if(isRegularBracketSequence(openPos,closePos)) return openPos;
	}
	return -1;
}

int main()
{
	//freopen("in","r",stdin);

	gets(s+1);

	len=strlen(s+1);

	linerTree=new LinerTree(1,len);

	for(int i=1;i<=len;i++)
	{
		state[i]=state[i-1];
		s[i]=='('?state[i]++:state[i]--;

		statePos[state[i]+MAX].push_back(i);

		linerTree->add(i,state[i]);
	}

	// debug
	//cout<<len<<endl;
	//for(int i=1;i<=len;i++) cout<<state[i]<<' ';cout<<endl;
	//for(int i=1;i<=len;i++) cout<<linerTree->query(i,i)<<' ';cout<<endl;

	int maxL=0,bestNum=1;

	for(int closePos=1;closePos<=len;closePos++) if(s[closePos]==')')
	{
		int openPos=findOpenPos(closePos,maxL);
		if(openPos==-1) continue;
		if(closePos-openPos+1>maxL)
		{
			maxL=closePos-openPos+1;
			bestNum=1;
		}
		else if(closePos-openPos+1==maxL) bestNum++;
	}

	printf("%d %d\n",maxL,bestNum);

	return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
    #define LL __int64
    #define ULL unsigned __int64
#else
    #define LL long long
    #define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

#define MAX 1000005

int SparseTable[22][2*MAX+1];
int Log[MAX];

void Make_SparseTable(int Length,int A[])
{
    for(int i=0;i<Length;i++) Log[i]=(int)(log(i+0.0)/log(2.0));
    for(int i=0;i<Length;i++) SparseTable[0][i]=i;
    for(int j=1;(1<<j)<=Length;j++) for(int i=0;i+(1<<j)<=Length;i++)
    {
        int p=SparseTable[j-1][i];
        int q=SparseTable[j-1][i+(1<<(j-1))];
        SparseTable[j][i]=(A[p]<A[q]?p:q);
    }
}

int RMQ(int L,int R,int A[])
{
    if(L>R) swap(L,R);
    int k=Log[R-L+1];
    L=SparseTable[k][L];
    R=SparseTable[k][R-(1<<k)+1];
    return (A[L]<A[R]?A[L]:A[R]);
}

int len;
char s[MAX];

int state[MAX];

vector<int> statePos[MAX+MAX];

int closeBracketNumber;
int closeBracketPos[MAX];

int findOpenPos(const vector<int> &pos,int closePos,int minL)
{
    int n=(int)pos.size();
    for(int i=0;i<n;i++)
    {
        int openPos=pos[i]+1;
        if(openPos>=closePos) return -1;
        if(closePos-openPos+1<minL) return -1;
        if(RMQ(openPos,closePos,state)>=state[openPos-1]) return openPos;
    }
    return -1;
}

int main()
{
    gets(s+1);

    len=strlen(s+1);

    if(s[1]=='(') statePos[MAX].push_back(0);

    closeBracketNumber=0;

    for(int i=1;i<=len;i++)
    {
        state[i]=state[i-1];
        s[i]=='('?state[i]++:state[i]--;

        if(s[i+1]=='(') statePos[state[i]+MAX].push_back(i);

        if(s[i]==')') closeBracketPos[closeBracketNumber++]=i;
    }

    Make_SparseTable(len+1,state);

    int maxL=0,bestNum=1;

    for(int i=0;i<closeBracketNumber;i++)
    {
        int closePos=closeBracketPos[i];
        int openPos=findOpenPos(statePos[state[closePos]+MAX],closePos,maxL);
        if(openPos==-1) continue;
        if(closePos-openPos+1>maxL)
        {
            maxL=closePos-openPos+1;
            bestNum=1;
        }
        else if(closePos-openPos+1==maxL) bestNum++;
    }

    printf("%d %d\n",maxL,bestNum);

    return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
    #define LL __int64
    #define ULL unsigned __int64
#else
    #define LL long long
    #define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF;
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

#define MAX 1000000+100

class LinerTree
{
private:
    int l,r;
    int minValue;
    LinerTree *leftChild,*rightChild;
public:
    LinerTree(){l=r=0;minValue=I_INF;leftChild=rightChild=NULL;}
    LinerTree(int l,int r):l(l),r(r)
    {
        minValue=I_INF;
        if(l==r)
        {
            leftChild=rightChild=NULL;
            return;
        }
        int mid=(l+r)>>1;
        leftChild=new LinerTree(l,mid);
        rightChild=new LinerTree(mid+1,r);
    }
    ~LinerTree()
    {
        if(leftChild)
        {
            leftChild->~LinerTree();
            delete leftChild;
        }
        if(rightChild)
        {
            rightChild->~LinerTree();
            delete rightChild;
        }
    }
    void add(int pos,int x)
    {
        if(l<=pos && pos<=r) checkMin(minValue,x);
        if(l==r) return;
        int mid=(l+r)>>1;
        if(pos<=mid) leftChild->add(pos,x);else rightChild->add(pos,x);
    }
    long query(int start,int end)
    {
        if(start<=l && r<=end) return minValue;
        int mid=(l+r)>>1;
        if(end<=mid) return leftChild->query(start,mid);
        else if(start>mid) return rightChild->query(start,end);
        else return min(leftChild->query(start,end),rightChild->query(start,end));
    }
};

int len;
char s[MAX];

int state[MAX];

LinerTree *linerTree;

bool isRegularBracketSequence(int start,int end)
{
    //cout<<start<<' '<<end<<' '<<state[end]-state[start-1]<<endl;
    if(state[end]-state[start-1]!=0) return false;
    if(linerTree->query(start,end)<state[start-1]) return false;
    return true;
}

int find(int l)
{
    if(l==0) return 0;
    int num=0;
    for(int i=1;i+l-1<=len;i++) if(isRegularBracketSequence(i,i+l-1)) num++;
    return num;
}

int main()
{

    gets(s+1);

    len=strlen(s+1);

    linerTree=new LinerTree(1,len);

    for(int i=1;i<=len;i++)
    {
        state[i]=state[i-1];
        s[i]=='('?state[i]++:state[i]--;

        linerTree->add(i,state[i]);
    }

    int L=1,R=len/2;

    int num;

    while(L<=R)
    {
        int mid=(L+R)/2;
        num=find(mid*2);
        if(num>0)
        {
            L=mid+1;
        }
        else R=mid-1;
    }

    int maxL=0,bestNum=1;

    num=find(L*2);
    if(num>0)
    {
        maxL=2*L;
        bestNum=num;
    }

    num=find(2*R);
    if(num>0)
    {
        maxL=2*R;
        bestNum=num;
    }

    printf("%d %d\n",maxL,bestNum);

    return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
    #define LL __int64
    #define ULL unsigned __int64
#else
    #define LL long long
    #define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

#define MAX 1000005

int SparseTable[20][2*MAX+1];
int Log[MAX];

void Make_SparseTable(int Length,int A[])
{
    for(int i=0;i<Length;i++) Log[i]=(int)(log(i+0.0)/log(2.0));
    for(int i=0;i<Length;i++) SparseTable[0][i]=i;
    for(int j=1;(1<<j)<=Length;j++) for(int i=0;i+(1<<j)<=Length;i++)
    {
        int p=SparseTable[j-1][i];
        int q=SparseTable[j-1][i+(1<<(j-1))];
        SparseTable[j][i]=(A[p]<A[q]?p:q);
    }
}

int RMQ(int L,int R,int A[])
{
    if(L>R) swap(L,R);
    int k=Log[R-L+1];
    L=SparseTable[k][L];
    R=SparseTable[k][R-(1<<k)+1];
    return (A[L]<A[R]?A[L]:A[R]);
}

int len;
char s[MAX];

int state[MAX];

vector<int> statePos[MAX+MAX];

int closeBracketNumber;
int closeBracketPos[MAX];

int findOpenPos(const vector<int> &pos,int closePos,int minL)
{
    int n=(int)pos.size();
    for(int i=0;i<n;i++)
    {
        int openPos=pos[i]+1;
        if(openPos>=closePos) return -1;
        if(closePos-openPos+1<minL) return -1;
        if(RMQ(openPos,closePos,state)>=state[openPos-1]) return openPos;
    }
    return -1;
}

int main()
{
    gets(s+1);

    len=strlen(s+1);

    if(s[1]=='(') statePos[MAX].push_back(0);

    closeBracketNumber=0;

    for(int i=1;i<=len;i++)
    {
        state[i]=state[i-1];
        s[i]=='('?state[i]++:state[i]--;

        if(s[i+1]=='(') statePos[state[i]+MAX].push_back(i);

        if(s[i]==')') closeBracketPos[closeBracketNumber++]=i;
    }

    Make_SparseTable(len+1,state);

    int maxL=0,bestNum=1;

    for(int i=0;i<closeBracketNumber;i++)
    {
        int closePos=closeBracketPos[i];
        int openPos=findOpenPos(statePos[state[closePos]+MAX],closePos,maxL);
        if(openPos==-1) continue;
        if(closePos-openPos+1>maxL)
        {
            maxL=closePos-openPos+1;
            bestNum=1;
        }
        else if(closePos-openPos+1==maxL) bestNum++;
    }

    printf("%d %d\n",maxL,bestNum);

    return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
	#define LL __int64
	#define ULL unsigned __int64
#else
	#define LL long long
	#define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF;
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

class LinerTree
{
private:
	int l,r;
	int minValue;
	LinerTree *leftChild,*rightChild;
public:
	LinerTree(){l=r=0;minValue=I_INF;leftChild=rightChild=NULL;}
	LinerTree(int l,int r):l(l),r(r)
	{
		minValue=I_INF;
		if(l==r)
		{
			leftChild=rightChild=NULL;
			return;
		}
		int mid=(l+r)>>1;
		leftChild=new LinerTree(l,mid);
		rightChild=new LinerTree(mid+1,r);
	}
	~LinerTree()
	{
		if(leftChild) leftChild->~LinerTree();
		if(rightChild) rightChild->~LinerTree();
		delete leftChild;
		delete rightChild;
	}
	void add(int pos,int x)
	{
		if(l<=pos && pos<=r) checkMin(minValue,x);
		if(l==r) return;
		int mid=(l+r)>>1;
		if(pos<=mid) leftChild->add(pos,x);else rightChild->add(pos,x);
	}
	int query(int start,int end)
	{
		if(start<=l && r<=end) return minValue;
		if(l==r) return minValue;
		int mid=(l+r)>>1;
		if(end<=mid) return leftChild->query(start,end);
		else if(start>mid) return rightChild->query(start,end);
		else return min(leftChild->query(start,end),rightChild->query(start,end));
	}
};

#define MAX 1000000+100

int len;
char s[MAX];

int state[MAX];

LinerTree *linerTree;

map<int,vector<int> > statePos;

bool isRegularBracketSequence(int start,int end)
{
	if((end-start+1)&0x1) return false;
	if(state[end]-state[start-1]!=0) return false;
	if(linerTree->query(start,end)<state[start-1]) return false;
	return true;
}

int findOpenPos(const vector<int> &pos,int closePos,int minL)
{
	int n=(int)pos.size();
	for(int i=0;i<n;i++)
	{
		int openPos=pos[i]+1;
		if(openPos>=closePos) return -1;
		if(closePos-openPos+1<minL) return -1;
		if((closePos-openPos+1)&0x1) continue;
		if(isRegularBracketSequence(openPos,closePos)) return openPos;
	}
	return -1;
}

int main()
{
	//freopen("in","r",stdin);

	gets(s+1);

	len=strlen(s+1);

	linerTree=new LinerTree(1,len);

	for(int i=1;i<=len;i++)
	{
		state[i]=state[i-1];
		s[i]=='('?state[i]++:state[i]--;

		statePos[state[i]].push_back(i);

		linerTree->add(i,state[i]);
	}

	// debug
	//cout<<len<<endl;
	//for(int i=1;i<=len;i++) cout<<state[i]<<' ';cout<<endl;
	//for(int i=1;i<=len;i++) cout<<linerTree->query(i,i)<<' ';cout<<endl;

	int maxL=0,bestNum=1;

	for(int closePos=1;closePos<=len;closePos++)
	{
		int openPos=findOpenPos(statePos[state[closePos]],closePos,maxL);
		if(openPos==-1) continue;
		if(closePos-openPos+1>maxL)
		{
			maxL=closePos-openPos+1;
			bestNum=1;
		}
		else if(closePos-openPos+1==maxL) bestNum++;
	}

	printf("%d %d\n",maxL,bestNum);

	return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
    #define LL __int64
    #define ULL unsigned __int64
#else
    #define LL long long
    #define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

#define MAX 1000005

int SparseTable[22][2*MAX+1];
int Log[MAX];

void Make_SparseTable(int Length,int A[])
{
    for(int i=0;i<Length;i++) Log[i]=(int)(log(i+0.0)/log(2.0));
    for(int i=0;i<Length;i++) SparseTable[0][i]=i;
    for(int j=1;(1<<j)<=Length;j++) for(int i=0;i+(1<<j)<=Length;i++)
    {
        int p=SparseTable[j-1][i];
        int q=SparseTable[j-1][i+(1<<(j-1))];
        SparseTable[j][i]=(A[p]<A[q]?p:q);
    }
}

int RMQ(int L,int R,int A[])
{
    if(L>R) swap(L,R);
    int k=Log[R-L+1];
    L=SparseTable[k][L];
    R=SparseTable[k][R-(1<<k)+1];
    return (A[L]<A[R]?A[L]:A[R]);
}

int len;
char s[MAX];

int state[MAX];

vector<int> statePos[MAX+MAX];

int closeBracketNumber;
int closeBracketPos[MAX];

int findOpenPos(const vector<int> &pos,int closePos,int minL)
{
    int n=(int)pos.size();
    for(int i=0;i<n;i++)
    {
        int openPos=pos[i]+1;
        if(openPos>=closePos) return -1;
        if(closePos-openPos+1<minL) return -1;
        if(RMQ(openPos,closePos,state)>=state[openPos-1]) return openPos;
    }
    return -1;
}

int main()
{
    gets(s+1);

    len=strlen(s+1);

    if(s[1]=='(') statePos[MAX].push_back(0);

    closeBracketNumber=0;

    for(int i=1;i<=len;i++)
    {
        state[i]=state[i-1];
        s[i]=='('?state[i]++:state[i]--;

        if(s[i+1]=='(') statePos[state[i]+MAX].push_back(i);

        if(s[i]==')') closeBracketPos[closeBracketNumber++]=i;
    }

    Make_SparseTable(len+1,state);

    int maxL=0,bestNum=1;

    for(int i=closeBracketNumber-1;i>0;i--)
    {
        int closePos=closeBracketPos[i];
        if(closePos<maxL) break;
        int openPos=findOpenPos(statePos[state[closePos]+MAX],closePos,maxL);
        if(openPos==-1) continue;
        if(closePos-openPos+1>maxL)
        {
            maxL=closePos-openPos+1;
            bestNum=1;
        }
        else if(closePos-openPos+1==maxL) bestNum++;
    }

    printf("%d %d\n",maxL,bestNum);

    return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
	#define LL __int64
	#define ULL unsigned __int64
#else
	#define LL long long
	#define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

#define MAX 1000005

int SparseTable[22][2*MAX+1];
int Log[MAX];

void Make_SparseTable(int Length,int A[])
{
	for(int i=0;i<Length;i++) Log[i]=(int)(log(i+0.0)/log(2.0));
    for(int i=0;i<Length;i++) SparseTable[0][i]=i;
    for(int j=1;(1<<j)<=Length;j++) for(int i=0;i+(1<<j)<=Length;i++)
    {
        int p=SparseTable[j-1][i];
        int q=SparseTable[j-1][i+(1<<(j-1))];
        SparseTable[j][i]=(A[p]<A[q]?p:q);
    }
}

int RMQ(int L,int R,int A[])
{
    if(L>R) swap(L,R);
    int k=Log[R-L+1];
    L=SparseTable[k][L];
    R=SparseTable[k][R-(1<<k)+1];
    return (A[L]<A[R]?A[L]:A[R]);
}

int len;
char s[MAX];

int state[MAX];

vector<int> statePos[MAX+MAX];

int closeBracketNumber;
int closeBracketPos[MAX];

int findOpenPos(const vector<int> &pos,int closePos,int minL)
{
	int n=(int)pos.size();
	for(int i=0;i<n;i++)
	{
		int openPos=pos[i]+1;
		if(openPos>=closePos) return -1;
		if(closePos-openPos+1<minL) return -1;
		if(RMQ(openPos,closePos,state)>=state[openPos-1]) return openPos;
	}
	return -1;
}

int main()
{
	gets(s+1);

	len=strlen(s+1);

	if(s[1]=='(') statePos[MAX].push_back(0);

	closeBracketNumber=0;

	for(int i=1;i<=len;i++)
	{
		state[i]=state[i-1];
		s[i]=='('?state[i]++:state[i]--;

		if(s[i+1]=='(') statePos[state[i]+MAX].push_back(i);

		if(s[i]==')') closeBracketPos[closeBracketNumber++]=i;
	}

	Make_SparseTable(len+1,state);

	int maxL=0,bestNum=1;

	for(int i=closeBracketNumber-1;i>0;i--)
	{
		int closePos=closeBracketPos[i];
		int openPos=findOpenPos(statePos[state[closePos]+MAX],closePos,maxL);
		if(openPos==-1) continue;
		if(closePos-openPos+1>maxL)
		{
			maxL=closePos-openPos+1;
			bestNum=1;
		}
		else if(closePos-openPos+1==maxL) bestNum++;
	}

	printf("%d %d\n",maxL,bestNum);

	return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
    #define LL __int64
    #define ULL unsigned __int64
#else
    #define LL long long
    #define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF;
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

#define MAX 1000000+100

class LinerTree
{
private:
    int l,r;
    int minValue;
    LinerTree *leftChild,*rightChild;
public:
    LinerTree(){l=r=0;minValue=I_INF;leftChild=rightChild=NULL;}
    LinerTree(int l,int r):l(l),r(r)
    {
        minValue=I_INF;
        if(l==r)
        {
            leftChild=rightChild=NULL;
            return;
        }
        int mid=(l+r)>>1;
        leftChild=new LinerTree(l,mid);
        rightChild=new LinerTree(mid+1,r);
    }
    ~LinerTree()
    {
        if(leftChild)
        {
            leftChild->~LinerTree();
            delete leftChild;
        }
        if(rightChild)
        {
            rightChild->~LinerTree();
            delete rightChild;
        }
    }
    void add(int pos,int x)
    {
        if(l<=pos && pos<=r) checkMin(minValue,x);
        if(l==r) return;
        int mid=(l+r)>>1;
        if(pos<=mid) leftChild->add(pos,x);else rightChild->add(pos,x);
    }
    long query(int start,int end)
    {
        if(start<=l && r<=end) return minValue;
        int mid=(l+r)>>1;
        if(end<=mid) return leftChild->query(start,mid);
        else if(start>mid) return rightChild->query(start,end);
        else return min(leftChild->query(start,end),rightChild->query(start,end));
    }
};

int len;
char s[MAX];

int state[MAX];

LinerTree *linerTree;

bool isRegularBracketSequence(int start,int end)
{
    //cout<<start<<' '<<end<<' '<<state[end]-state[start-1]<<endl;
    if(state[end]-state[start-1]!=0) return false;
    if(linerTree->query(start,end)<state[start-1]) return false;
    return true;
}

int find(int l)
{
    int num=0;
    for(int i=1;i+l-1<=len;i++) if(isRegularBracketSequence(i,i+l-1)) num++;
    return num;
}

int main()
{

    gets(s+1);

    len=strlen(s+1);

    linerTree=new LinerTree(1,len);

    for(int i=1;i<=len;i++)
    {
        state[i]=state[i-1];
        s[i]=='('?state[i]++:state[i]--;

        linerTree->add(i,state[i]);
    }

    // debug
    //cout<<len<<endl;
    //for(int i=1;i<=len;i++) cout<<state[i]<<' ';cout<<endl;

    int L=1,R=len/2;

    int maxL=0,bestNum=1;

    while(L<=R)
    {
        int mid=(L+R)/2;
        int num=find(mid*2);
        //cout<<mid*2<<' '<<num<<endl;
        if(num>0)
        {
            L=mid+1;
            maxL=mid*2;
            bestNum=num;
        }
        else R=mid-1;
    }

    printf("%d %d\n",maxL,bestNum);

    return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
    #define LL __int64
    #define ULL unsigned __int64
#else
    #define LL long long
    #define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF;
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

class LinerTree
{
private:
    int l,r;
    int minValue;
    LinerTree *leftChild,*rightChild;
public:
    LinerTree(){l=r=0;minValue=I_INF;leftChild=rightChild=NULL;}
    LinerTree(int l,int r):l(l),r(r)
    {
        minValue=I_INF;
        if(l==r)
        {
            leftChild=rightChild=NULL;
            return;
        }
        int mid=(l+r)>>1;
        leftChild=new LinerTree(l,mid);
        rightChild=new LinerTree(mid+1,r);
    }
    ~LinerTree()
    {
        if(leftChild) leftChild->~LinerTree();
        if(rightChild) rightChild->~LinerTree();
        delete leftChild;
        delete rightChild;
    }
    void add(int pos,int x)
    {
        if(l<=pos && pos<=r) checkMin(minValue,x);
        if(l==r) return;
        int mid=(l+r)>>1;
        if(pos<=mid) leftChild->add(pos,x);else rightChild->add(pos,x);
    }
    int query(int start,int end)
    {
        if(start<=l && r<=end) return minValue;
        if(l==r) return minValue;
        int mid=(l+r)>>1;
        if(end<=mid) return leftChild->query(start,end);
        else if(start>mid) return rightChild->query(start,end);
        else return min(leftChild->query(start,end),rightChild->query(start,end));
    }
};

#define MAX 1000000+100

int len;
char s[MAX];

int state[MAX];

LinerTree *linerTree;

map<int,vector<int> > statePos;

bool isRegularBracketSequence(int start,int end)
{
    if((end-start+1)&0x1) return false;
    if(state[end]-state[start-1]!=0) return false;
    if(linerTree->query(start,end)<state[start-1]) return false;
    return true;
}

int findOpenPos(const vector<int> &pos,int closePos,int minL)
{
    int n=(int)pos.size();
    for(int i=0;i<n;i++)
    {
        int openPos=pos[i]+1;
        if(openPos>=closePos) return -1;
        if(closePos-openPos+1<minL) return -1;
        if(s[openPos]!='(') continue;
        if(isRegularBracketSequence(openPos,closePos)) return openPos;
    }
    return -1;
}

int main()
{
    gets(s+1);

    len=strlen(s+1);

    linerTree=new LinerTree(1,len);

    for(int i=1;i<=len;i++)
    {
        state[i]=state[i-1];
        s[i]=='('?state[i]++:state[i]--;

        statePos[state[i]].push_back(i);

        linerTree->add(i,state[i]);
    }

    int maxL=0,bestNum=1;

    for(int closePos=1;closePos<=len;closePos++) if(s[closePos]==')')
    {
        int openPos=findOpenPos(statePos[state[closePos]],closePos,maxL);
        if(openPos==-1) continue;
        if(closePos-openPos+1>maxL)
        {
            maxL=closePos-openPos+1;
            bestNum=1;
        }
        else if(closePos-openPos+1==maxL) bestNum++;
    }

    printf("%d %d\n",maxL,bestNum);

    return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
	#define LL __int64
	#define ULL unsigned __int64
#else
	#define LL long long
	#define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF;
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

class LinerTree
{
private:
	int l,r;
	int minValue;
	LinerTree *leftChild,*rightChild;
public:
	LinerTree(){l=r=0;minValue=I_INF;leftChild=rightChild=NULL;}
	LinerTree(int l,int r):l(l),r(r)
	{
		minValue=I_INF;
		if(l==r)
		{
			leftChild=rightChild=NULL;
			return;
		}
		int mid=(l+r)>>1;
		leftChild=new LinerTree(l,mid);
		rightChild=new LinerTree(mid+1,r);
	}
	~LinerTree()
	{
		if(leftChild) leftChild->~LinerTree();
		if(rightChild) rightChild->~LinerTree();
		delete leftChild;
		delete rightChild;
	}
	void add(int pos,int x)
	{
		if(l<=pos && pos<=r) checkMin(minValue,x);
		if(l==r) return;
		int mid=(l+r)>>1;
		if(pos<=mid) leftChild->add(pos,x);else rightChild->add(pos,x);
	}
	int query(int start,int end)
	{
		if(start<=l && r<=end) return minValue;
		if(l==r) return minValue;
		int mid=(l+r)>>1;
		if(end<=mid) return leftChild->query(start,end);
		else if(start>mid) return rightChild->query(start,end);
		else return min(leftChild->query(start,end),rightChild->query(start,end));
	}
};

#define MAX 1000000+100

int len;
char s[MAX];

int state[MAX];

LinerTree *linerTree;

vector<int> statePos[MAX+MAX];

bool isRegularBracketSequence(int start,int end)
{
	if((end-start+1)&0x1) return false;
	if(state[end]-state[start-1]!=0) return false;
	if(linerTree->query(start,end)<state[start-1]) return false;
	return true;
}

int findOpenPos(int closePos,int minL)
{
	int nowState=state[closePos]+MAX;
	for(int i=0;i<(int)statePos[nowState].size();i++)
	{
		int openPos=statePos[nowState][i]+1;
		if(openPos>=closePos) return -1;
		if(closePos-openPos+1<minL) return -1;
		if(s[openPos]!='(') continue;
		if((closePos-openPos+1)&0x1) continue;
		if(isRegularBracketSequence(openPos,closePos)) return openPos;
	}
	return -1;
}

int main()
{
	//freopen("in","r",stdin);

	gets(s+1);

	len=strlen(s+1);

	linerTree=new LinerTree(1,len);

	for(int i=1;i<=len;i++)
	{
		state[i]=state[i-1];
		s[i]=='('?state[i]++:state[i]--;

		statePos[state[i]+MAX].push_back(i);

		linerTree->add(i,state[i]);
	}

	// debug
	//cout<<len<<endl;
	//for(int i=1;i<=len;i++) cout<<state[i]<<' ';cout<<endl;
	//for(int i=1;i<=len;i++) cout<<linerTree->query(i,i)<<' ';cout<<endl;

	int maxL=0,bestNum=1;

	for(int closePos=1;closePos<=len;closePos++) if(s[closePos]==')')
	{
		int openPos=findOpenPos(closePos,maxL);
		if(openPos==-1) continue;
		if(closePos-openPos+1>maxL)
		{
			maxL=closePos-openPos+1;
			bestNum=1;
		}
		else if(closePos-openPos+1==maxL) bestNum++;
	}

	printf("%d %d\n",maxL,bestNum);

	return 0;
}


#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>

#ifdef RUN_ON_WINDOWS
    #define LL __int64
    #define ULL unsigned __int64
#else
    #define LL long long
    #define ULL unsigned long long
#endif

#define EPS 1E-9
#define D_INF 1E99
#define I_INF 0x7FFFFFFF;
#define L_INF 0x7FFFFFFFFFFFFFFFLL

using namespace std;

template<class T>inline void checkMax(T &a,const T &b){if(a<b) a=b;}
template<class T>inline void checkMin(T &a,const T &b){if(b<a) a=b;}
template<class T>inline string toString(const T &n){ostringstream out;out<<n;out.flush();return out.str();}
template<class T>inline T toValue(const string &s){T x;istringstream in(s);in>>x;return x;}

int dx[]={ 0, 0,-1, 1,-1, 1,-1, 1};
int dy[]={-1, 1, 0, 0,-1,-1, 1, 1};
string dir[]={"L","R","U","D","LU","LD","RU","RD"};

#define MAX 1000000+100

class LinerTree
{
private:
    int l,r;
    int minValue;
    LinerTree *leftChild,*rightChild;
public:
    LinerTree(){l=r=0;minValue=I_INF;leftChild=rightChild=NULL;}
    LinerTree(int l,int r):l(l),r(r)
    {
        minValue=I_INF;
        if(l==r)
        {
            leftChild=rightChild=NULL;
            return;
        }
        int mid=(l+r)>>1;
        leftChild=new LinerTree(l,mid);
        rightChild=new LinerTree(mid+1,r);
    }
    ~LinerTree()
    {
        if(leftChild) leftChild->~LinerTree();
        if(rightChild) rightChild->~LinerTree();
        delete leftChild;
        delete rightChild;
    }
    void add(int pos,int x)
    {
        if(l<=pos && pos<=r) checkMin(minValue,x);
        if(l==r) return;
        int mid=(l+r)>>1;
        if(pos<=mid) leftChild->add(pos,x);else rightChild->add(pos,x);
    }
    int query(int start,int end)
    {
        if(start<=l && r<=end) return minValue;
        if(l==r) return minValue;
        int mid=(l+r)>>1;
        if(end<=mid) return leftChild->query(start,end);
        else if(start>mid) return rightChild->query(start,end);
        else return min(leftChild->query(start,end),rightChild->query(start,end));
    }
};

int len;
char s[MAX];

int state[MAX];

LinerTree *linerTree;

bool isRegularBracketSequence(int start,int end)
{
    if(state[end]-state[start-1]!=0) return false;
    if(linerTree->query(start,end)<state[start-1]) return false;
    return true;
}

int find(int l)
{
    if(l==0) return 0;
    int num=0;
    for(int i=1;i+l-1<=len;i++) if(isRegularBracketSequence(i,i+l-1)) num++;
    return num;
}

int main()
{
    gets(s+1);

    len=strlen(s+1);

    linerTree=new LinerTree(1,len);

    for(int i=1;i<=len;i++)
    {
        state[i]=state[i-1];
        s[i]=='('?state[i]++:state[i]--;

        linerTree->add(i,state[i]);
    }

    int maxL=0,bestNum=1;

    int L=1,R=len/2;

    while(L<=R)
    {
        int mid=(L+R)/2;
        int num=find(mid*2);
        if(num>0)
        {
            L=mid+1;
            if(maxL<2*mid)
            {
                maxL=2*mid;
                bestNum=num;
            }
        }
        else R=mid-1;
    }

    printf("%d %d\n",maxL,bestNum);

    return 0;
}


#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <ctime>
#include <iomanip>
#include <iterator>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <stdio.h>
#include <cstring>

#define ii <int , int>

#define mp make_pair
#define all(v) v.begin(),v.end()
#define loop(i, n) for (int i = 0; i < n; i++)
#define pb push_back
#define sz(v) (int)v.size()
#define X first
#define Y second

#define Pi(x) printf("%d ", (x))
#define Pii(x, y) printf("%d %d ", (x), (y))
#define Piii(x, y, z) printf("%d %d %d", (x), (y), (z))
#define Pl(x) printf("%I64d ", (x))
#define Pll(x, y) printf("%I64d I64d ", (x), (y))
#define Plll(x, y, z) printf("%I64d I64d I64d ", (x), (y), (z))
#define Ps(x) printf("%s", (x))
#define Pe() printf("\n")
#define Pe1(i) for (int j = 0; j < i; j++) printf(" ")

#define Si(x) scanf("%d",&x)
#define Sii(x, y) scanf("%d %d", (&x), (&y))
#define Siii(x, y, z) scanf("%d %d %d", (&x), (&y), (&z))
#define Sl(x) scanf("%I64d", (&x))
#define Sll(x, y) scanf("%I64d %I64d", (&x), (&y))
#define Slll(x, y, z) scanf("%I64d %I64d %I64d", (&x), (&y), (&z))
#define Ss(x) scanf("%s", (&x))

using namespace std;

typedef long long ll;
typedef vector<int > vi;
typedef vector<vi> vvi;
typedef pair ii pii;
typedef vector <pii> vii;
typedef map ii mii;
typedef set <int > si;
typedef multiset <int > msi;
typedef multimap <int , int> mmi;
typedef vector <ll> vl;
typedef pair<ll, ll> pll;
typedef vector <pll> vll;

const ll nInf = -1000000000;
const ll pInf = 1000000000;
const ll mod    = 1000000007;
const int MAXN = 1e6 + 10;

void getdata();
void preproc();
void solve();
char s[MAXN];
int n;

int main()
{
	//freopen( "input.txt", "r" , stdin);
	//freopen( "output.txt", "w" , stdout);
	int t = 1;
	//scanf("%d", &t);
	for (int i = 0;i < t; i++)
	{
		getdata();
		preproc();
		solve();
	}
	return 0;
}

void getdata()
{
	scanf("%s", &s);
	n = strlen(s);
}

void preproc()
{

}

void solve()
{
	int bal = 0;
	int f = 0;
	int am = 1;
	int maxres = 0;

	for (int i = 0;i < n; i++)
	{
		if (s[i] == ')') bal--;
		else bal++;
		if (bal < 0)
		{
			bal = 0;
			f = i + 1;
		}
		else if (bal == 0)
		{
			if (maxres < i - f + 1)
			{
				maxres = i - f + 1;
				am = 1;
			}
			else if (maxres == i - f + 1)
			{
				am++;
			}
		}
	}
	printf("%d %d\n", maxres, am);
}


#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <ctime>
#include <iomanip>
#include <iterator>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <stdio.h>
#include <cstring>

#define ii <int , int>

#define mp make_pair
#define all(v) v.begin(),v.end()
#define loop(i, n) for (int i = 0; i < n; i++)
#define pb push_back
#define sz(v) (int)v.size()
#define X first
#define Y second

#define Pi(x) printf("%d ", (x))
#define Pii(x, y) printf("%d %d ", (x), (y))
#define Piii(x, y, z) printf("%d %d %d", (x), (y), (z))
#define Pl(x) printf("%I64d ", (x))
#define Pll(x, y) printf("%I64d I64d ", (x), (y))
#define Plll(x, y, z) printf("%I64d I64d I64d ", (x), (y), (z))
#define Ps(x) printf("%s", (x))
#define Pe() printf("\n")
#define Pe1(i) for (int j = 0; j < i; j++) printf(" ")

#define Si(x) scanf("%d",&x)
#define Sii(x, y) scanf("%d %d", (&x), (&y))
#define Siii(x, y, z) scanf("%d %d %d", (&x), (&y), (&z))
#define Sl(x) scanf("%I64d", (&x))
#define Sll(x, y) scanf("%I64d %I64d", (&x), (&y))
#define Slll(x, y, z) scanf("%I64d %I64d %I64d", (&x), (&y), (&z))
#define Ss(x) scanf("%s", (&x))

using namespace std;

typedef long long ll;
typedef vector<int > vi;
typedef vector<vi> vvi;
typedef pair ii pii;
typedef vector <pii> vii;
typedef map ii mii;
typedef set <int > si;
typedef multiset <int > msi;
typedef multimap <int , int> mmi;
typedef vector <ll> vl;
typedef pair<ll, ll> pll;
typedef vector <pll> vll;

const ll nInf = -1000000000;
const ll pInf = 1000000000;
const ll mod    = 1000000007;
const int MAXN = 1e6 + 10;

void getdata();
void preproc();
void solve();
char s[MAXN];
int n;

int main()
{
	//freopen( "input.txt", "r" , stdin);
	//freopen( "output.txt", "w" , stdout);
	int t = 1;
	//scanf("%d", &t);
	for (int i = 0;i < t; i++)
	{
		getdata();
		preproc();
		solve();
	}
	return 0;
}

void getdata()
{
	scanf("%s", &s);
	n = strlen(s);
}

void preproc()
{

}

void solve()
{
	int bal = 0;
	int f = 0;
	int am = 1;
	int maxres = 0;
	si pos;
	for (int i = 0;i < n; i++)
	{
		if (s[i] == ')') bal--;
		else bal++;
		if (bal < 0)
		{
			pos.clear();
			bal = 0;
			f = -1;
		}
		else if (bal >= 0)
		{
			if (s[i] == '(')
			{
				pos.insert(i);
			}
			else
			{
				si::iterator it = pos.end();
				it--;
				if (f == -1)
					f = (*it);
				else
					f = min((*it), f);
				int curres = i - f + 1;

				if (maxres < curres)
				{
					maxres = curres;
					am = 1;
				}
				else if (maxres == curres)
				{
					am++;
				}
				pos.erase(it);
			}
		}
	}
	printf("%d %d\n", maxres, am);
}


#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <ctime>
#include <iomanip>
#include <iterator>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <stdio.h>
#include <cstring>

#define ii <int , int>

#define mp make_pair
#define all(v) v.begin(),v.end()
#define loop(i, n) for (int i = 0; i < n; i++)
#define pb push_back
#define sz(v) (int)v.size()
#define X first
#define Y second

#define Pi(x) printf("%d ", (x))
#define Pii(x, y) printf("%d %d ", (x), (y))
#define Piii(x, y, z) printf("%d %d %d", (x), (y), (z))
#define Pl(x) printf("%I64d ", (x))
#define Pll(x, y) printf("%I64d I64d ", (x), (y))
#define Plll(x, y, z) printf("%I64d I64d I64d ", (x), (y), (z))
#define Ps(x) printf("%s", (x))
#define Pe() printf("\n")
#define Pe1(i) for (int j = 0; j < i; j++) printf(" ")

#define Si(x) scanf("%d",&x)
#define Sii(x, y) scanf("%d %d", (&x), (&y))
#define Siii(x, y, z) scanf("%d %d %d", (&x), (&y), (&z))
#define Sl(x) scanf("%I64d", (&x))
#define Sll(x, y) scanf("%I64d %I64d", (&x), (&y))
#define Slll(x, y, z) scanf("%I64d %I64d %I64d", (&x), (&y), (&z))
#define Ss(x) scanf("%s", (&x))

using namespace std;

typedef long long ll;
typedef vector<int > vi;
typedef vector<vi> vvi;
typedef pair ii pii;
typedef vector <pii> vii;
typedef map ii mii;
typedef set <int > si;
typedef multiset <int > msi;
typedef multimap <int , int> mmi;
typedef vector <ll> vl;
typedef pair<ll, ll> pll;
typedef vector <pll> vll;

const ll nInf = -1000000000;
const ll pInf = 1000000000;
const ll mod    = 1000000007;
const int MAXN = 1e6 + 10;

void getdata();
void preproc();
void solve();
char s[MAXN];
int n;

int main()
{
	freopen( "input.txt", "r" , stdin);
	freopen( "output.txt", "w" , stdout);
	int t = 1;
	//scanf("%d", &t);
	for (int i = 0;i < t; i++)
	{
		getdata();
		preproc();
		solve();
	}
	return 0;
}

void getdata()
{
	scanf("%s", &s);
	n = strlen(s);
}

void preproc()
{

}

void solve()
{
	int bal = 0;
	int f = 0;
	int am = 1;
	int maxres = 0;

	for (int i = 0;i < n; i++)
	{
		if (s[i] == ')') bal--;
		else bal++;
		if (bal < 0)
		{
			bal = 0;
			f = i + 1;
		}
		else if (bal == 0)
		{
			if (maxres < i - f + 1)
			{
				maxres = i - f + 1;
				am = 1;
			}
			else if (maxres == i - f + 1)
			{
				am++;
			}
		}
	}
	printf("%d %d\n", maxres, am);
}


#include <iostream>
#include <fstream>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <ctime>
#include <iomanip>
#include <iterator>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <stdio.h>
#include <cstring>

#define ii <int , int>

#define mp make_pair
#define all(v) v.begin(),v.end()
#define loop(i, n) for (int i = 0; i < n; i++)
#define pb push_back
#define sz(v) (int)v.size()
#define X first
#define Y second

#define Pi(x) printf("%d ", (x))
#define Pii(x, y) printf("%d %d ", (x), (y))
#define Piii(x, y, z) printf("%d %d %d", (x), (y), (z))
#define Pl(x) printf("%I64d ", (x))
#define Pll(x, y) printf("%I64d I64d ", (x), (y))
#define Plll(x, y, z) printf("%I64d I64d I64d ", (x), (y), (z))
#define Ps(x) printf("%s", (x))
#define Pe() printf("\n")
#define Pe1(i) for (int j = 0; j < i; j++) printf(" ")

#define Si(x) scanf("%d",&x)
#define Sii(x, y) scanf("%d %d", (&x), (&y))
#define Siii(x, y, z) scanf("%d %d %d", (&x), (&y), (&z))
#define Sl(x) scanf("%I64d", (&x))
#define Sll(x, y) scanf("%I64d %I64d", (&x), (&y))
#define Slll(x, y, z) scanf("%I64d %I64d %I64d", (&x), (&y), (&z))
#define Ss(x) scanf("%s", (&x))

using namespace std;

typedef long long ll;
typedef vector<int > vi;
typedef vector<vi> vvi;
typedef pair ii pii;
typedef vector <pii> vii;
typedef map ii mii;
typedef set <int > si;
typedef multiset <int > msi;
typedef multimap <int , int> mmi;
typedef vector <ll> vl;
typedef pair<ll, ll> pll;
typedef vector <pll> vll;

const ll nInf = -1000000000;
const ll pInf = 1000000000;
const ll mod    = 1000000007;
const int MAXN = 1e6 + 10;

void getdata();
void preproc();
void solve();
char s[MAXN];
int n;

int main()
{
	//freopen( "input.txt", "r" , stdin);
	//freopen( "output.txt", "w" , stdout);
	int t = 1;
	//scanf("%d", &t);
	for (int i = 0;i < t; i++)
	{
		getdata();
		preproc();
		solve();
	}
	return 0;
}

void getdata()
{
	scanf("%s", &s);
	n = strlen(s);
}

void preproc()
{

}

void solve()
{
	int bal = 0;
	int f = 0;
	int am = 1;
	int maxres = 0;
	si pos;
	for (int i = 0;i < n; i++)
	{
		if (s[i] == ')') bal--;
		else bal++;
		if (bal < 0)
		{
			pos.clear();
			bal = 0;
			f = -1;
		}
		else if (bal > 0)
		{
			if (s[i] == '(')
			{
				pos.insert(i);
			}
			else
			{
				si::iterator it = pos.end();
				it--;
/*				if (f == -1)
					f = (*it);
				else
					f = min((*it), f);*/
				int curres = i - (*it) + 1;

				if (maxres < curres)
				{
					maxres = curres;
					am = 1;
				}
				else if (maxres == curres)
				{
					am++;
				}
				pos.erase(it);
			}
		}
		else if (bal == 0)
		{
				si::iterator it = pos.end();
				it--;
				if (f == -1)
					f = (*it);
				else
					f = min((*it), f);
				int curres = i - f + 1;

				if (maxres < curres)
				{
					maxres = curres;
					am = 1;
				}
				else if (maxres == curres)
				{
					am++;
				}
				pos.erase(it);

		}
	}
	printf("%d %d\n", maxres, am);
}