Description
可怜的小国和小辉在双十一过后,吃饭都吃不起了,只能在吃饭时间玩会游戏来打发时间。可是时间久了之后,他们各种游戏都玩了一遍,所以他们两个打算合作出一个新奇的游戏。最终,他们决定先做四个纸箱,每个纸箱里面放1000张卡片,每张卡片上写一个数字。
小国从不同的两个纸箱里抽两张卡片,卡片上的数字是a和b,小辉从另外两个不同的纸箱里抽两张卡片,卡片上的数字是c和d。然后两个人分别用特定的计算方法计算一个结果。计算方法是小国计算a^b的值,然后将该值的各位数字的和计算出来,小辉计算c^d的值,然后将该值的各位数字的和计算出来,如果他们各自得到的和不是一位数,那么继续分别计算各自的各个位数的和。最后小国将他计算出来的数字扩大2017倍,然后用新得到值的素因子和作为分子,小辉将他计算出来的数字扩大1203倍,然后用新得到的值的素因子和作为分母,得出一个分数,并且将这个分数化简为最简分数。
可是小辉和小国的数学都很差,想请热爱编程的你帮忙计算这个最简分数。
Input
输入T(1<=T<=50),表示有T组输入
接下来T行数据,每行有四个整数a,b,c,d(0
Output
每行输出一个答案,答案用最简分数表示。
Sample Input
2
5 2 2 6
2 9 3 6
Sample Output
506/101
2019/404
解题思路
因为a,b,c,d的范围都在10^3,所以问题的关键在于如何求解a^b和其最终一位数的各位数字之和,解法就是在用快速幂求解a^b的过程中直接对9取模。原因就是任意一个数化简为最终一位数的结果即为该数%9,推理过程:
假设这个数为456,一方面456->4+5+6=15->1+5=6,另一方面456%9=(400+50+6)%9=(4*100%9+5*10%9+6%9)%9=(4+5+6)%9=15%9=(10+5)%9=(1*10%9+5%9)=1+5=6。得证
代码实现
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int mul1[10]= {0,0,2,3,2,5,5,7,2,3};
int mul2[10]= {0,0,2,0,2,5,2,7,2,0};
int quick_pow(int x,int y)
{
int ans=1;
x%=9;
while(y)
{
if(y%2)
ans=ans*x%9;
x=x*x%9;
y/=2;
}
return ans==0?9:ans;
}
int main()
{
ios::sync_with_stdio(false);
int T;
int a,b,c,d;
cin>>T;
while(T--)
{
cin>>a>>b>>c>>d;
int t1=2017+mul1[quick_pow(a,b)];
int t2=404+mul2[quick_pow(c,d)];
int gcd=__gcd(t1,t2);
cout<<t1/gcd<<"/"<<t2/gcd<<endl;
}
return 0;
}
当然,我没有如此强大的脑回路,第一时间想到的就是a^i各位数字之和化简为一位数一定是有规律的,我坚定的认为就是这样,打了表发现差不多!如当a=7时,因为7^1->7,7^2->4,7^3->1,7^4=7……,所以其循环节为3,则最终的结果取决于b%3。但在打表的过程中会发现当这个数a的各位数字之和为3,6,9时,a^1即为3,6,9,否则就始终为9,这里需要单独判断。
不过要注意在求循环节的过程中,只要遇到结果为1就直接退出,1就代表着循环节的结束。如果再多计算一次就会爆ll,导致结果错误。
代码实现
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll mark[100007];
bool vis[10]={0,0,0,1,0,0,1,0,0,1}; //用来判断一个数是否是3,6,9
int mul1[10]= {0,0,2,3,2,5,5,7,2,3}; //a^b各位数字之和化简为一位数时该数的各素因子之和
int mul2[10]= {0,0,2,0,2,5,2,7,2,0}; //同上,求c^d相关,但是素因子包括3的不计算在内,因为分母*1203,1203的素因子包括3和401,不能重复计算
ll getnum(ll a) //只获取一个数的各位数字之和
{
ll t,num=a;
while(!(num>=0&&num<10))
{
t=num;
num=0;
while(t>0)
{
num+=t%10;
t/=10;
}
}
return num;
}
ll geta(int a,int b) //获取一个数各位数字之和最终化简为一位数的结果
{
ll n=(ll)a;
mark[1]=getnum(a); //该数的各位数字之和
ll countt=1,i; //countt标记a^i最终一位数遵循规律的循环节的长度,如7^1->7,7^2->4,7^3->1,7^4=7……,所以其循环节为3.
for(i=2;; i++)
{
n*=a;
mark[i]=getnum(n); //标记循环节的值
if(mark[i]==1)break; //出现1即代表将进入新的循环,退出即可
}
countt=i;
if(b%countt==0)
return mark[countt];
return mark[b%countt]; //返回a^b,c^d化简的最终结果
}
int main()
{
ios::sync_with_stdio(false);
int T;
ll a,b,c,d;
ll ta,tb;
cin>>T;
while(T--)
{
cin>>a>>b>>c>>d;
int numa=getnum(a); //获取a的各位数字之和
int numc=getnum(c);
ta=-1,tb=-1;
if(vis[numa]) //如果numa为3,6,9,则a^1=numa,否则即为9
{
if(vis[numa])
{
if(b==1) ta=numa;
else ta=9;
}
}
if(vis[numc])
{
if(vis[numc])
{
if(d==1) tb=numc;
else tb=9;
}
}
if(ta==-1)
ta=geta(a,b);
if(tb==-1)
tb=geta(c,d);
ll fenzi=mul1[ta]+2017; //分子的素因子之和
ll fenmu=mul2[tb]+404;
ll gcd=__gcd(fenzi,fenmu); //约分化简
cout<<fenzi/gcd<<"/"<<fenmu/gcd<<endl;
}
return 0;
}