链接:https://ac.nowcoder.com/acm/contest/903/B
来源:牛客网
解析:
一开始想用逆元,但发现q-1不一定和mod互质,所以不能用直接逆元
ac:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,q,p;
ll mult(ll a,ll b,ll p) {
ll r=0;
ll t=a;
while(b) {
if(b&1) r=(r+t)%p;
t=(t<<1)%p;
b>>=1;
}
return r;
}
ll qpow(ll a,ll b,ll mod)
{
ll ans=1;
while(b)
{
if(b&1) ans=mult(ans,a,mod)%mod;
a=(mult(a,a,mod))%mod;
b>>=1;
}
return ans%mod;
}
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>q>>n>>p;
ll k=qpow(q,n+1,p*(q-1))-q;
k=k/(q-1);
printf("%lld\n",k);
}
return 0;
}
因为包含取模,无法直接逆元所以这里用公式递归求
求等比为k的等比数列之和S[n]:
当n为偶数..S[n] = S[n/2] + pow(k,n/2) * S[n/2]
当n为奇数...S[n] = S[n/2] + pow(k,n/2) * S[n/2] + pow(k,n)等比数列第n个数的值
直接递归求解
ac:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,q,p;
ll qpow(ll a,ll b,ll mod)
{
ll res=1;
while(b)
{
if(b&1)
res=(res*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return res;
}
ll solve(ll q,ll n,ll p)
{
if(n==1)
return q%p;
if(n%2==0)
return (1+qpow(q,n/2,p))*solve(q,n/2,p)%p;
else
return ((1+qpow(q,n/2,p))*solve(q,n/2,p)%p+qpow(q,n,p))%p;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%lld%lld%lld",&q,&n,&p);
printf("%lld\n",solve(q,n,p));
}
return 0;
}
余数之和:https://vjudge.net/problem/HYSBZ-1257
解析:
取模的意义:
求=>=>
后面可以用整除分块解决,复杂度就降为
整除分块整除分块代码:
for(int l=1,r;l<=n;l=r+1)
{
r=n/(n/l);
ans+=(r-l+1)*(n/l);
}
代码:
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
int main()
{
ll k,n,ans,sum=0;
cin>>n>>k;
ans=k*n;//整除分块代码+等差数列求和
if(k<=n)
{
for(int l=1,r;l<=k;l=r+1)
{
r=k/(k/l);
sum+=(r-l+1)*(k/l)*(l+r)>>1;
}
}
else{
for(int l=1,r;l<=n;l=r+1)//k>n,r<=n
{
r=min(k/(k/l),n);
sum+=(r-l+1)*(k/l)*(l+r)>>1;
}
}
printf("%lld\n",ans-sum);
return 0;
}
https://vjudge.net/contest/313367#problem/E
题意:
给1个数n,输出4个数,这四个数和为n,且都是素数
如果无法输出,则输出:Impossible.
解析:
哥德巴赫猜想的一个扩展,首先筛素数
根据猜想得:
如果n<8,肯定无法输出
如果为偶数,分解为:2 2 x n-4-x
如果为奇数,分解为:2 3 x n-5-x
暴力枚举
ac:
#include<bits/stdc++.h>
#define ll long long
#define MAXN 10000005
using namespace std;
int prime[MAXN];//保存素数
bool vis[MAXN];//初始化
int cnt;
void getprime(int n)
{
cnt=0;
memset(vis,0,sizeof(vis));
for(int i=2;i<n;i++)
{
if(!vis[i])
prime[cnt++]=i;
for(int j=0;j<cnt&&i*prime[j]<n;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0)
break;
}
}
}
int main()
{
ll n;
getprime(10000001);
while(scanf("%lld",&n)!=EOF)
{
if(n<8)
{
printf("Impossible.\n");
}
else{
if(n%2==1)
{
for(int i=2;i<n-5;i++)
{
if(vis[i]==0&&vis[n-i-5]==0)
{
printf("2 3 %d %d\n",i,n-i-5);
break;
}
}
}
else{
for(int i=2;i<n-4;i++)
{
if(vis[i]==0&&vis[n-i-4]==0)
{
printf("2 2 %d %d\n",i,n-i-4);
break;
}
}
}
}
}
return 0;
}
https://vjudge.net/problem/HDU-2421
题意:
给定一个数n=A^B,求该数的因子的因子数的立方和
例如:
n=2^2,因子有1,2,4,因子数1,2,3,ans=(1)^3+(2)^3+(3)^3=36
解析:
唯一分解定理
积性函数:对于任意互质的整数a和b有性质f(ab)=f(a)*f(b)的数论函数
学习链接:https://www.cnblogs.com/zhoushuyu/p/8275530.html
立方和公式:1^3 + 2^3 + …… n^3 = (1+2+3+...+n)^2 = (n (n+1) / 2)^2
补一个平方和公式:1^2+2^2+...+n^3=n*(n+1)*(2*n+1)/6
这里将A唯一分解得:A=a1^p1*a2^p2*....an^pn,因子数为:(1+p1)*(1+p2)*(1+p3)*...(1+pn)
这里有次方=>因子数为:(1+p1*b)*(1+p2*b)*(1+p3*b)*....*(1+pn*b).
ans=(1+p1*b)^3+(1+p2^b)^3+....+(1+pn^b)^3
ans=[(1+p1*b)*(1+p1*b+1)/2]^2+....[(1+pn*b)*(1+pn*b+1)/2]^2
ac:
#include<bits/stdc++.h>
#define mod 10007
#define ll long long
#define MAXN 1005
using namespace std;
int pri[MAXN];
int sumx[MAXN];
int index=0;
//pri是素因子,sumx是该素因子上的指数b,第一个素因子坐标为0
void getpri(ll m)//分解质因数
{
index=0;
memset(sumx,0,sizeof(sumx));
for(ll i=2;i*i<=m;i++)
{
while(m%i==0)
{
pri[index]=i;
sumx[index]++;
m/=i;
}
if(sumx[index]) index++;
}
if(m>1) pri[index]=m, sumx[index++]=1;
}
int main()
{
ll a,b,cas=1;
while(scanf("%lld%lld",&a,&b)!=EOF)
{
getpri(a);
ll sum=1;
for(int i=0;i<index;i++)
{
ll n=(sumx[i]*b+1)%mod;//(1+pi*b)
ll s=((n)*(n+1)/2)%mod;//s=n*(n+1)/2
sum=(sum*((s*s)%mod))%mod;//sum+=s*s;
}
printf("Case %lld: %lld\n",cas++,sum);
}
return 0;
}
https://vjudge.net/problem/HDU-4542
题意:
1.求最小的因子数为k的数
2.求最小的(n-因子数)==k的数
解析:
对于2,答案可能没有,如果有,呢么不会很大
对于1,答案肯定有,如果是一个很大的素数,呢么就肯定会超过2^62
例如:17359,这个凑不出因子,只能是2的指数,肯定大于2^62
我们暴力1e19以内的所以情况
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#define ll long long
using namespace std;
unsigned ll n;
unsigned ll prime[17]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,51};
unsigned ll cc[220005];
void dfs(int pos,int len,unsigned ll q,int num)//第pos个素数,前一位素因子指数len,num当前因子个数,q为该数的值
{
if(q<cc[num])//对于同样数目的因子,我们取最小的数,存起来
cc[num]=q;
ll g=1;
for(int i=1;i<=len;i++)
{
g=g*prime[pos];
if(n/g<q)//不能用q*g<n,会越界
break;
dfs(pos+1,i,q*g,num*(i+1));
}
}
int vis[100005]={0};
int b[500005];
void init()
{
for(int i=1;i<=100000;i++)
{
b[i]=1e9;
for(int j=1;j*i<=100000;j++)
vis[j*i]++;
}
for(int i=1;i<=100000;i++)
{
vis[i]=i-vis[i];
b[vis[i]]=min(b[vis[i]],i);
}
}
int main()
{
int t,ty,k,cas=1;
for(int i=0;i<=50000;i++)
cc[i]=1e19;
n=1e19;
dfs(1,62,1,1);//这里最小的2的指数最多62
init();
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&ty,&k);
printf("Case %d: ",cas++);
if(ty==0)
{
if(cc[k]==1e19)
printf("INF\n");
else
printf("%lld\n",cc[k]);
}
else{
if(b[k]==1e9)
printf("Illegal\n");
else
printf("%d\n",b[k]);
}
}
return 0;
}
https://vjudge.net/problem/HDU-5584
题意:
1只青蛙只能向下或者向右跳,如果在(x,y)坐标,它可以跳到(x+lcm(x,y),y)或者(x,y+lcm(x,y));
给你青蛙的终点,它能从多少种坐标过来
解析:
1.如果x>y,lcm(x,y)>=x,y,所以一定是坐标大的被改变了,回跳以后,路径还是只有一个,所以路径唯一
2.设gcd(x,y)=k,x=nk,y=mk,lcm(x,y)=nmk,那么下一步能走到(n(m+1)k,mk)或者(nk,m(n+1)k),并且由于n(m+1)与m互质,n与m(n+1)互质,所以下一步的gcd依然是k.
3.根据以上两点,就可以用逆推找出答案,每次都假设x>y,x=nk,y=mk,当前点就是由(x/(y/k+1),y)走到的,如果x不再是(y+k)的倍数(即:(y/k+1)*k的倍数),则表示不能再逆推
ac:
#include<cstdio>
#include<algorithm>
using namespace std;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int main(){
int x,y,T;
scanf("%d",&T);
for(int cas=1;cas<=T;cas++){
scanf("%d%d",&x,&y);
if(x<y) swap(x,y);
int k=gcd(x,y),cnt=1;
while(x%(y+k)==0){
cnt++;
x=x/(y/k+1);
if(x<y) swap(x,y);
}
printf("Case #%d: %d\n",cas,cnt);
}
return 0;
}
我自己用的笨办法,假设ex较大,我发现
ex=x+lcm(x,ey)=>ex=x+x*ey/gcd(x,ey)=x(1+ey)/gcd(x,ey),直接枚举x,x是ex的因子,耗时较大
ac:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll gcd(ll a,ll b) {while(b^=a^=b^=a%=b);return a;}
int main()
{
ll t,ex,ey,cas=1;
cin>>t;
while(t--)
{
int cnt=0;
cin>>ex>>ey;
if(ex<ey)
swap(ex,ey);
ll ga=-1,gb=-1;
while(1)
{
for(int i=1;i*i<=ex;i++)
{
if(ex%i==0)
{
int x=i;
if(x*(1+ey/gcd(ey,x))==ex){
cnt++;
ex=x;
break;
}
x=ex/i;
if(x*(1+ey/(gcd(ey,x)))==ex){
cnt++;
ex=x;
break;
}
}
}
if(ex<ey)
swap(ex,ey);
if(ga==ex&&gb==ey)
break;
ga=ex,gb=ey;
}
printf("Case #%lld: %d\n",cas++,cnt+1);
}
return 0;
}
/*
3
6 10
6 8
2 8
*/
https://vjudge.net/problem/POJ-3101
题意:
n个行星开始在一条直线上且在同一边,问你最少再过多久,他们会再一次全面在同一直线上
解析:
ui=2*π/Ti,选择行星0为参考点,行星i的相对角速度为
t1=(T0*T1)/(2*(abs(T1-T0))
import java.math.*;
import java.util.*;
public class Main {
public static void main(String[ ] args)
{
Scanner cin = new Scanner(System.in);
int n,cnt;
int [ ] t =new int[1100];
int [ ]s = new int [1100];
BigInteger a,b,g,mo = null,de = null;
while(cin.hasNext())
{
n = cin.nextInt();
for(int i = 0;i<n;i++)
s[i] = cin.nextInt();
for(int i = 1;i<n;i++)
{
a = BigInteger.valueOf(s[i]*s[0]);//t0*t1
b = BigInteger.valueOf(Math.abs(s[i]-s[0])*2);//2*(t0-t1)
g = a.gcd(b);
if(i == 1)
{
mo = a.divide(g);
de = b.divide(g);
}
else
{
a = a.divide(g);
b = b.divide(g);
mo = mo.multiply(a).divide(mo.gcd(a));
de = de.gcd(b);
}
}
System.out.println(mo+" "+de);
}
cin.close();
}
}
https://vjudge.net/problem/CodeForces-1114C
求n!下末尾0的个数
解析:
x在b进制下,可以写成a*b^k
等价于n!%(b^k)==0的最大k
要求 n! 在 b 进制下有多少个尾 0 就相当于 求 n! % (b^k) == 0 的最大 k。
那么我们现在把 n! 看作一个数 A。问题就是 求 A % (b^k) == 0 的最大 k;
我们知道有素数分解定理: b = p1^a1 * p2^a2 * p3^a3 ...;
那么我们如果可以求得 A 里面 p1^b1 * p2^b2 * p3^b3 ... 的 b1, b2, b3...
那么答案 遍历所有b中质因子^ai,求最小指数ans = min(ans,bi/ai )
ac:
#include<bits/stdc++.h>
#define ll long long
#define N 10010
using namespace std;
const ll MAXN=1e18+1;
ll pri[N];//质因子
ll sumx[N];//该质因子的指数最大值
ll index=0;//可以分解出多少个质因子
void getpri(ll m)//质因数分解
{
for(ll i=2;i*i<=m;i++)
{
while(m%i==0)
{
pri[index]=i;
sumx[index]++;
m/=i;
}
if(sumx[index]) index++;
}
if(m>1) pri[index]=m, sumx[index++]=1;
}
ll getsumx(ll n,ll p)//n!能分解出sumX个p
{ //返回n!中p因子的指数
ll sumX=0;
while(n>0)
{
sumX+=n/p;
n/=p;
}
return sumX;
}
int main()
{
ll n,b,ans=MAXN;
scanf("%I64d%I64d",&n,&b);
getpri(b);
for(ll i=0;i<index;i++)
{
ans=min(ans,getsumx(n,pri[i])/sumx[i]);
}
printf("%I64d",ans);
return 0;
}
https://vjudge.net/problem/Gym-101981J
题意:
给定n个数
令,=,求
解析:
对于一个点ai,求
n-i+1是后面的区间端点总数,i是前面的区间端点总数
但是在这里,一个区间内素因子可能重复,i的效果肯定小于(n-i+1)*(i)
对于在i位置一个素因子,我们规定向后取满,对于最靠近i的前面重复的在j位置我们同一个素因子
i位置的素因子在前面取到的最大端点为(i-j),这个素因子的贡献为(n-i+1)*(i-j)
线筛a[i]的素因子,保存每个素因子出现的位置
对所以素因子求贡献
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#define MAXN 1000005
#define ll long long
using namespace std;
int tot;
int isprime[MAXN];
int prime[MAXN];
int a[MAXN];
vector<int> pos[MAXN];//保存素数
void get_prime() //欧拉筛
{
tot=0;
memset(isprime,1,sizeof(isprime));
isprime[0]=isprime[1]=0;
for(int i=2;i<=MAXN;i++)
{
if(isprime[i]) prime[tot++]=i;
for(int j=0;j<tot;j++)
{
if(i*prime[j]>MAXN) break;
isprime[i*prime[j]]=0;
if(i%prime[j]==0) break;
}
}
}
void dec(int p)//分解素因子
{
int n=a[p];
for(int i=0;i<tot&&prime[i]*prime[i]<=n;i++)
{
if(n%prime[i]==0)
{
pos[prime[i]].push_back(p);//保存素因子存在的位置
while(n%prime[i]==0)
n/=prime[i];
}
}
if(n>1) pos[n].push_back(p);
}
int main()
{
int n;
get_prime();
scanf("%d",&n);
for(int i=0;i<tot;i++)
pos[prime[i]].push_back(0);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
dec(i);
}
ll sum=0;
for(int i=0;i<tot;i++)
{
for(int j=1;j<pos[prime[i]].size();j++)
{
sum+=(ll)(n+1-pos[prime[i]][j])*(pos[prime[i]][j]-pos[prime[i]][j-1]);
}
}
printf("%lld\n",sum);
return 0;
}
https://vjudge.net/problem/HDU-4002
解析:
求 2到n之间 n/phi(n) 为最大值时的n.
phi(n)=n*(1-1/p1)*(1-1/p2)*......(1-1/pk)
即求:(1-1/p1)*(1-1/p2)*......(1-1/pk)
自然是素因子越多越好
由此
2=2;
6=2*3;
30=2*3*5;
120=2*3*5*7;
2310=2*3*5*7*11;
ac:
#include<stdio.h>
#include<iostream>
#include<string.h>
#define ll long long
#define MAXN 1005
#define L 100005
using namespace std;
bool isprime[MAXN];
int prime[MAXN];
int tot=0;
int na[L];
string xc[1001];
void getprime(int N)//素数筛
{
memset(isprime,true,sizeof(isprime));
memset(prime,0,sizeof(prime));
isprime[0]=false;
isprime[1]=false;
for(int i=2;i<=N;i++)
{
if(isprime[i])
prime[++tot]=i;
for(int j=1;j<=tot&&i*prime[j]<N;j++)
{
isprime[i*prime[j]]=false;
if(!(i%prime[j]))
break;
}
}
}
string mul(string a,ll b)//高精度a乘单精度b
{
string ans;
ll La=a.size();
fill(na,na+L,0);
for(int i=La-1;i>=0;i--) na[La-i-1]=a[i]-'0';
ll w=0;
for(int i=0;i<La;i++) na[i]=na[i]*b+w,w=na[i]/10,na[i]=na[i]%10;
while(w) na[La++]=w%10,w/=10;
La--;
while(La>=0) ans+=na[La--]+'0';
return ans;
}
int cmp(string a,string b)//简单正整数比较
{
int lena=a.size();
int lenb=b.size();
if(lena>lenb)
return 1;
else if(lena<lenb)
return -1;
else{
for(int i=0;i<lena;i++)
{
if(a[i]-'0'>b[i]-'0')
return 1;
else if(a[i]-'0'<b[i]-'0')
return -1;
}
return 0;
}
}
int bsearch(int n, string key)//二分查找
{
int low = 0;
int high = n;
int mid = 0;
while(low <= high) {
mid = low + ((high-low) >> 1);
if(cmp(key,xc[mid])==0||cmp(key,xc[mid])==-1){
high = mid - 1;
} else {
low = mid + 1;
}
}
return low <= n ? low : -1;
}
int main()
{
std::ios::sync_with_stdio(false);
int x,y,sum,t;
string cc="1",ct;
getprime(MAXN);
for(int i=1;i<=55;i++)
{
cc=mul(cc,prime[i]);
xc[i]=cc;
if(cc.size()>100)
break;
}
cin>>t;
while(t--)
{
cin>>ct;
int q=bsearch(54,ct);
if(xc[q].compare(ct)==0)
cout<<xc[q]<<endl;
else cout<<xc[q-1]<<endl;
}
return 0;
}
B. Goldbach
题意:
t组测试数据
给一个n(偶数),2<=n<2^63,将n分解为两个素数
输出两个素数,结果符合就可以
ac:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
typedef unsigned long long ll;
using namespace std;
ll add_mod(ll a,ll b,ll mod){
ll ans=0;
while(b){
if(b&1)
ans=(ans+a)%mod;
a=a*2%mod;
b>>=1;
}
return ans;
}
ll pow_mod(ll a,ll n,ll mod){
if(n>1){
ll tmp=pow_mod(a,n>>1,mod)%mod;
tmp=add_mod(tmp,tmp,mod);
if(n&1) tmp=add_mod(tmp,a,mod);
return tmp;
}
return a;
}
bool Miller_Rabbin(ll n,ll a){
ll d=n-1,s=0,i;
while(!(d&1)){
d>>=1;
s++;
}
ll t=pow_mod(a,d,n);
if(t==1 || t==-1)
return 1;
for(i=0;i<s;i++){
if(t==n-1)
return 1;
t=add_mod(t,t,n);
}
return 0;
}
bool is_prime(ll n){
ll i,tab[4]={3,4,7,11};
for(i=0;i<4;i++){
if(n==tab[i])
return 1;
if(!n%tab[i])
return 0;
if(n>tab[i] && !Miller_Rabbin(n,tab[i]))
return 0;
}
return 1;
}
bool isprime[1000001];
int prime[1000001];
int tot=0;
void getprime(int N)
{
memset(isprime,true,sizeof(isprime));
memset(prime,0,sizeof(prime));
isprime[0]=false;
isprime[1]=false;
for(int i=2;i<=N;i++)
{
if(isprime[i])
prime[++tot]=i;
for(int j=1;j<=tot&&i*prime[j]<N;j++)
{
isprime[i*prime[j]]=false;
if(!(i%prime[j]))
break;
}
}
}
int main()
{
int t;
getprime(1000000);
cin>>t;
while(t--)
{
ll n,m;
cin>>n;
for(int i=1;i<tot;i++)
{
m=n-prime[i];
if(is_prime(m))
{
cout<<prime[i]<<" "<<m<<endl;
break;
}
}
}
return 0;
}
https://codeforces.com/problemset/problem/906/D
题意:
给你1~n的wi,让你求这种式子,q次询问,每次询问wl^wl+1^wl+2^....^wr
解析:
广义欧拉降幂
如果b^c>phi(p):,否则次方就不加phi(p)
我们可以递归求解.
求a^b^c,先求b^c%phi(p),一直递归下去,如果phi(p)==1,就没有必要递归下去了.
我们改一下快速幂函数,让他对于大于mod的值,返回res%mod+mod.
这里询问非常多,我们还要将phi记忆化,避免重复求phi,否则会超时
ac:
#include<bits/stdc++.h>
#define MAXN 100005
#define ll long long
using namespace std;
ll w[MAXN];
unordered_map<ll,ll> p;
ll MOD(ll a,ll b)
{
if(a>b)
return a=a%b+b;
else
return a;
}
ll phi(ll n)
{
if(p[n]!=0)
return p[n];
ll res = n,k=n;
for (ll i = 2; i*i <= n; i++)
if (n%i == 0)
{
res =res/i*(i-1);
while(n%i == 0)
n /= i;
}
if (n > 1)
res = res/n*(n-1);
p[k]=res;//算出的答案存起来,避免重复计算
return res;
}
ll qpow(ll a,ll b,ll mod)
{
ll ans=1;
while(b)
{
if(b&1) ans=ans*a,ans=MOD(ans,mod);
a=a*a,a=MOD(a,mod);
b>>=1;
}
return ans;
}
ll solve(ll l,ll r,ll mod)
{
if(l==r||mod==1)
return MOD(w[l],mod);
return qpow(w[l],solve(l+1,r,phi(mod)),mod);
}
int main()
{
ll n,k,l,r;
ll m;
while(scanf("%lld%lld",&n,&m)!=EOF)
{
for(ll i=1;i<=n;i++)
scanf("%lld",&w[i]);
scanf("%lld",&k);
for(ll i=1;i<=k;i++)
{
scanf("%lld%lld",&l,&r);
printf("%lld\n",solve(l,r,m)%m);
}
}
return 0;
}
http://codeforces.com/gym/102028/problem/E
题意:
RR=1/(1/R1+1/R2+1/R3+....+1/Rn)
Ri=i,如果i的因子有一个数的二次,Ri就为无穷大
Si={j,i%j==0},Si包含i的所以因子
解析:
为了让RR竟可能的小,呢就就让1/R1+1/R2+....+1/R2,尽可能的大,竟可能的多
=>Ri越小越好,然后Ri的集合有是一个数的因子,呢么如果Ri与Rj相等,呢么Ri*Rj为d^2,无穷大,倒一下->0,白白多加一个因子
再根据测试数据,很容易退出10->1,2,3 选择连续素数的积<=n
1/(1/1+1/2+1/3)=1/2
这里n非常大,用java过
ac:
import javafx.scene.transform.Scale;
import org.omg.Messaging.SYNC_WITH_TRANSPORT;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
int prime[]=new int[1005],k=1;
prime[1]=1;
for(int a=2;a<=500;a++){
int sign=0;
for(int b=2;b*b<=a;b++){
if(a%b==0){
sign=1;
break;
}
}
if(sign==0){
prime[++k]=a;
}
}
Scanner in=new Scanner(System.in);
int t;
t=in.nextInt();
while(t!=0)
{
BigInteger AA,BB,c,EE,DD;
BB= BigInteger.valueOf(1);
AA=in.nextBigInteger();
EE=BigInteger.valueOf(1);
DD=BigInteger.valueOf(1);
for(int i=2;i<=k;i++)
{
c=BigInteger.valueOf(prime[i]);
BB = BB.multiply(c);
if(BB.compareTo(AA)==1){
break;
}
EE=EE.multiply(c.add(BigInteger.valueOf(1)));
DD=BB;
}
BigInteger gcc=EE.gcd(DD);
System.out.println(DD.divide(gcc)+"/"+EE.divide(gcc));
t--;
}
}
}