CSES - Shared codeLink to this code: https://cses.fi/paste/e0e917d7faed57ac1ae15c/
#include <bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp> 
#include <ext/pb_ds/tree_policy.hpp> 
using namespace __gnu_pbds; 
#define indexed_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update> 
//find_by_order = returns pointer to element at that pos
//order_of_key = returns pos of the given element
#define indexed_multiset tree<int, null_type,less_equal<int>, rb_tree_tag,tree_order_statistics_node_update>
#define all(x)  (x).begin(),(x).end() 
#define mem1(a)  memset(a,-1,sizeof(a))
#define mem0(a)  memset(a,0,sizeof(a))  
#define int long long
#define endl "\n"
typedef vector<int> vi;
typedef pair<int,int> pi;
#define F first
#define S second
#define PB push_back
#define MP make_pair
#define rep(i,a,b) for (int i = a; i <b; i++)
#define MOD 1000000007
#define boost
#define debug1(x) cout<<#x<<" "<<x<<endl;
#define debug2(x,y) cout<<#x<<" "<<x<<" "<<#y<<" "<<y<<endl;
#define debug3(x,y,z) cout<<#x<<" "<<x<<" "<<#y<<" "<<y<<" "<<#z<<" "<<z<<endl;
template<typename T1,typename T2>istream& operator>>(istream& in,pair<T1,T2> &a){in>>a.F>>a.S;return in;}
template<typename T1,typename T2>ostream& operator<<(ostream& out,pair<T1,T2> a){out<<a.F<<" "<<a.S;return out;}
template<class _T>inline void read(_T &_a)
{
    bool f=0; char _c=getchar(); _a=0;
    while(_c<'0'||_c>'9'){ if(_c=='-') f=1; _c=getchar(); }
    while(_c>='0'&&_c<='9'){ _a=(_a<<3)+(_a<<1)-'0'+_c; _c=getchar(); }
    if(f) _a=-_a;
}

const long long INF=1e18;
int T;

int mod_pow(int a,int b)
{
    if(b==0) return 1;
    if(b==1) return a%MOD;
    int temp=mod_pow(a,b/2);
    if(b%2==0) return (temp*temp)%MOD;
    else return (((temp*temp)%MOD)*a)%MOD;
}

int modInverse(int A)
{
    return mod_pow(A,MOD-2);
}
 __int128_t mod_pow2( __int128_t a, __int128_t b)
{
    if(b==0) return 1;
    if(b==1) return a%MOD;
     __int128_t temp=mod_pow(a,b/2);
    if(b%2==0) return (temp*temp)%MOD;
    else return (((temp*temp)%MOD)*a)%MOD;
}



int32_t main()
{ 
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
   int n;
   cin>>n;
   map<int,int> mp;
   int mn=1;
   int l,r;
   for(int i=1;i<=n;i++)
   {
       cin>>l>>r;
       mp[l] = r;
       mn = (mn%MOD * (mod_pow(l,r)))%MOD;
       
   }
   

   int ans2 = 1;
   int ans1 =1;
   __int128_t an=1;

   for(auto q : mp)
   {
       ans1 = (ans1%MOD * (q.second+1)%MOD)%MOD;
       an = an*(q.second+1);
       int temp = ((mod_pow(q.first,q.second+1)-1)*modInverse(q.first-1))%MOD;
       temp = temp%MOD;
       ans2 = ((ans2%MOD * temp%MOD)%MOD);
   }

    int ans3 = mod_pow2(mn,an/2);

   cout<<ans1<<" "<<ans2<<" "<<ans3<<endl;


   

	// you should actually read the stuff at the bottom
 
/* stuff you should look for
	* int overflow, array bounds
	* special cases (n=1?)
	* do smth instead of nothing and stay organized
	* WRITE STUFF DOWN
	* DON'T GET STUCK ON ONE APPROACH
*/
return 0;
}