小国的游戏(素数因子和)

欢迎访问https://blog.csdn.net/lxt_Lucia~~

宇宙第一小仙女\(^o^)/~~萌量爆表求带飞=≡Σ((( つ^o^)つ~dalao们点个关注呗~~


emmm....这是上学期趣味编程大赛的一个题,现在看起来感觉也还是of great significance的。这里介绍两种不同的思路,目前均已通过测试,大家放心看bo~


Problem is coming ~~~~~~

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

emmm....题意看起来有点麻烦有点绕,不过没关系的咯~慢慢来嘛.....but当然是不能直接暴力的咯~

下面先介绍第一种思路吼~

方法一:

1.思路:

(1)先进行素数打表,首先假定一定范围内的每个数都为素数,令其下标对应的值均为0,再筛出素数,使其下标对应的值为1,即常说的素数筛法。

(2)计算(a^b)%c,因为其值有可能会超,therefore,利用公式(a*b)%c=[(a%c)*(b%c)]%c 分别来求 a^b 和 c^d 的mode之后的值,再按照题意分别乘2017和1203。

(3)分别求素数因子和,素数因子,即素数&&因子(其下标对应的数值为0即为素数,%i为0即为因子)。

(4)因为最后得出的结果分子分母要进行约分,所以调用gcd函数求二者的最大公因数,再同除得出结果即可。

2.话不多说,上代码咯:

#include<bits/stdc++.h>
using namespace std;
int check[100010];
void f(){
     int i,j;
     memset(check,0,sizeof(check));
     check[1]=1;
     for(i=2;i*i<=100010;i++){
         if(!check[i]){
            for(j=i*i;j<=100010;j+=i)
                check[j]=1;
         }
     }
}
int gcd(int a,int b){
    return a==0?b:gcd(b%a,a);
}
int main()
{
    int a,b,c,d,T,i,k,sum1,sum2,fh1,fh2,mfactor;
    scanf("%d",&T);
    f();
    for(k=1;k<=T;k++){
        sum1=1;sum2=1;fh1=0;fh2=0;
        scanf("%d%d%d%d",&a,&b,&c,&d);
        for(i=1;i<=b;i++){
            sum1=sum1*a%9;
            sum1%=9;
            if(sum1==0)
               sum1=9;
        }
        for(i=1;i<=d;i++){
            sum2=sum2*c%9;
            sum2%=9;
            if(sum2==0)
                sum2=9;
        }
        sum1*=2017;
        sum2*=1203;
        for(i=2;i<=sum1;i++){
            if(check[i]==0&&sum1%i==0)
                fh1+=i;
        }
        for(i=2;i<=sum2;i++){
             if(check[i]==0&&sum2%i==0)
                 fh2+=i;
        }
        mfactor=gcd(fh1,fh2);
        printf("%d/%d\n",fh1/mfactor,fh2/mfactor);
   }
   return 0;
}

--------------------------------------------我只是两种思路的分界线---------------------------------------

下面介绍第二种方法咯~这个方法是从另一位大大佬那里看到的,长姿势了...据说还是千千大佬的女队友。。。emmm...反正也是大大佬就对了嘛。。。大佬博客地址:https://blog.csdn.net/so_so_y/article/details/78640552#comments

方法二:

1.思路:

因为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。得证。

2.上代码

#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;
}

宇宙第一小仙女\(^o^)/~~萌量爆表求带飞=≡Σ((( つ^o^)つ~dalao们没事多来瞅瞅咯~~

欢迎访问https://blog.csdn.net/lxt_Lucia~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值