DIDIDI loves to take a shower(乘法逆元)

本文介绍了一道有趣的算法题目——澡堂挑战。该问题要求计算在特定条件下最少需要洗澡的次数,以避免“godie”。文章提供了两种解决方案,一种经常超时,另一种则通过扩展欧几里得算法和线性同余方程成功解决该问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DIDIDI loves to take a shower
时间限制:1000ms 内存限制:65535KB
提交总数:5 通过人数:0

题目描述
DIDIDI 是爱洗澡的好孩子,每次洗完澡后,B天之内一定要再洗一次澡,否则就会go die。
澡堂子每A天关一天门。

求:在DIDIDI不go die的情况下,每A天至少要洗几次澡
输入格式
第一行一个正整数t,代表数据组数。
接下来的t行,每行两个正整数A和B

1 <= t <= 2000
2 <= A,B <= 108
输出格式
对于每组样例,输出一行这样:
Case #i: ans

Case空格#编号:(半角)空格答案
i从1开始
ans……自己看吧,要求化简
样例输入

2
7 3
7 4

样例输出

Case #1: 5/2
Case #2: 2

提示
第一组样例:
可以理解为每周日关门,那么就是:
周三,周六,周二,周五,周一,周四,周六,周二,周五,周一,周四。
相当于两周去5次。

第二组样例:
周三,周六,周三,周六
一周去2次。
一直TLE 最后问了一个大神 先贴上大神的代码

#include <iostream>
#include <vector>
using namespace std;
long long ex_gcd(long long a,long long b,long long &x,long long &y)
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    else
    {
        long long r=ex_gcd(b,a%b,y,x);
        y-=x*(a/b);
        return r;
    }
}
vector<long long> line_mod_equ(long long a,long long b,long long n)
{
    long long x,y;
    long long d=ex_gcd(a,n,x,y);
    vector<long long> ans;
    ans.clear();
    if(b%d==0)
    {
        x=((x%n)+n)%n;
        ans.push_back(x*(b/d)%(n/d));
        for(int i=1;i<d;i++)
            ans.push_back((ans[0]+i*n/d)%n);
    }
    return ans;
}
int main()
{
    int t;
    cin>>t;
    for(int k=1;k<=t;k++)
    {
        long long a,b,x,y,ansa=0,ansb=0,gg;
        long long tempx,tempy;
        double ttt=0;
        cin>>a>>b;
        gg=ex_gcd(a,b,x,y);
        if(gg==1)
        {
            vector<long long> v=line_mod_equ(a%b,b-1,b);
            for(int i=0;i<v.size();i++)
            {
                tempx=v[i];
                tempy=(a*tempx+1)/b;
                if(tempy*ansb<=ansa*tempx)
                {
                    ansa=tempy;
                    ansb=tempx;
                    gg=ex_gcd(ansa,ansb,x,y);
                    ansa/=gg;
                    ansb/=gg;
                }
            }
        }
        else
        {
            ansa=a/gg;
            ansb=b/gg;
        }
        if(ansb==1)
            cout<<"Case #"<<k<<": "<<ansa<<endl;
        else
            cout<<"Case #"<<k<<": "<<ansa<<"/"<<ansb<<endl;
    }
    return 0;
}

再贴上我超时的代码

#include<iostream>
#include<string>
#include<algorithm>
#include<set>
#include<queue>
#include<vector>
#include<math.h>
#include<string.h>
#include<stdio.h>
using namespace std;
long long gcd(long long a,long long b)
{
    long long tt ;
    if(a>b)
    {
        tt = a;
        a = b;
        b = tt;
    }
    while(b)
    {
        tt = a%b;
        a = b;
        b = tt;
    }
    return a;
}
int main(void)
{
    int ncase,num=1;
    cin >> ncase;
    while(ncase--)
    {
        long long A,B,cnt=1;
        scanf("%lld %lld",&A,&B);
        printf("Case #%d: ",num++);
        if(A%B == 0)
        {
            printf("%lld\n",A/B);
            continue;
        }
        long long gd = gcd(A,B);
        if(gd!=1)
        {
            printf("%lld/%lld\n",A/gd,B/gd);
            continue;
        }
        long long t = A;
        while(1)
        {
            if((A+1) % B == 0)
            {
                long long tt = gcd((A+1)/B,cnt);
                if(cnt/tt == 1)
                    printf("%lld\n",(A+1)/B/tt);
                else
                    printf("%lld/%lld\n",(A+1)/B/tt,cnt/tt);
                break;
            }
            else if(A % B == 0)
            {
                long long tt = gcd((A)/B,cnt);
                if(cnt/tt == 1)
                    printf("%lld\n",(A)/B/tt);
                else
                    printf("%lld/%lld\n",(A)/B/tt,cnt/tt);
                break;
            }
            A += t;
            cnt++;
        }
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值