同余——《青蛙的约会》《最幸运的数字》

传送门:222. 青蛙的约会 - AcWing题库

思路:

首先回顾一下扩展欧几里得算法,一般是用来求形如使得ax+by = gcd(a,b)的方程成立的x,y值

其余可以看数学知识章通用模板_北岭山脚鼠鼠的博客-CSDN博客,接下来是一些之前没有提到的补充:

设d==gcd(a,b),对于求一些更一般的方程ax+by=c,这条式子有解当且仅当c%d==0,可以在求一组ax+by=gcd(a,b)的特解(x0,y0)之后将其乘上c/d就是ax+by=c的一组特解。

而这玩意的通解就是x=(c/d)*x0+k*(b/d)      y=(c/d)*y0+k*(a/d),其中k为任意整数。

回到题目: 

分析题意先假设A是在B的后面,最开始两只青蛙的位置相差(b-a),也就是A要追个(b-a)米,每一次跳跃A追B(m-n)米,在经历了x次跳跃之后的终于到达同一个位置,此时有(m-n)*x==b-a,或者说是已经跳过了一圈变成了(m-n)*x==b-a+L,又或者是已经跳过了k圈,变成了(m-n)*x==b-a+k*L

最终式子调换一下位置就变成了(m-n)*x-k*L==b-a,其中L和(m-n)和(b-a)都是已知量,可以完全用上面说的方法求解,不过求解之前同样要判断有无解,同时m-n的值有可能是负数,最后得到的dyoke能是负的,要转成正数。

代码:
 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=1e3+10;
typedef long long ll;
ll gcd(ll a,ll b,ll &x,ll &y)
{
    if(b==0) { x=1,y=0;return a;}
    ll d=gcd(b,a%b,x,y);
    ll z=x;
    x=y;
    y=z-y*(a/b);
    return d;
}
int main()
{
    ll a,b,m,n,l,x,y;
    cin>>a>>b>>m>>n>>l;
    ll d=gcd(m-n,l,x,y);
    if((b-a)%d) puts("Impossible");
    else
    {
        x*=(b-a)/d;
        ll p=l/d;
        if(p<0) p=-p;
        ll t=p;
        cout<<(x%t+t)%t<<endl;
    }
    return 0;
}

传送门:202. 最幸运的数字 - AcWing题库

思路:

对于题目中的x个8组合而成的数字可以用一个8*(10^x-1)/9这条式子来表示。

设d为gcd(8,L).

对于题目的要求一定有8*(10^x-1)/9%L==0可得8*(10^x-1)%9L==0可得(10^x-1)%(9L/d)==0可得以下的式子10^x≡1(mod 9L/d),

由欧拉定理a^(φ(n))≡1(mod n)其中可以推出满足a^x≡1(mod n)的最小的x一定是的φ(n)约数,这里不给证明。证明略。

由此,只需要求出欧拉函数φ(9L/d),枚举其所有的约数,用快速幂逐一判断是否满足同余式。

另外有个前提条件,那就是9L/d必须要和10互质,不互质的话欧拉函数不成立,原式子也不成立。

代码:
 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int N=1e3+10;
typedef long long ll;

ll get_euler(ll c)
{
    ll res=c;
    for(int i=2;i<=c/i;i++)
    {
        if(c%i==0)
        {

            while(c%i==0) c/=i;
            res=res/i*(i-1);
        }
    }
    if(c>1) res=res/c*(c-1);
    return res;
}
ll qmul(ll a,ll k,ll b)
{
    ll res=0;
    while(k)
    {
        if(k&1) res=(res+a)%b;
        a=(a+a)%b;
        k>>=1;
    }
    return res;
}
ll qmi(ll a, ll k,ll p)
{
    ll res=1;
    while(k)
    {
        if(k&1) res=qmul(res,a,p); //会爆ll,要用快乘
        a=qmul(a,a,p);
        k>>=1;
    }
    return res;
}
int main()
{
    int T=1;
    ll l;
    while(cin>>l,l)
    {
        ll d=1;
        while(l%(d*2)==0&&d*2<=8) d*=2; //获取最大公因数
        ll c=9*l/d;
      ll res=1e18;
        ll p=get_euler(c); //
        if(c%2==0||c%5==0) res=0; //判断是否约数
        else
        for(ll d=1;d*d<=p;d++) //试除法枚举约数
            if(p%d==0)
            {
                if(qmi(10,d,c)==1) res=min(res,d);
                if(qmi(10,p/d,c)==1) res=min(res,p/d);
            }
        printf("Case %d: %lld\n",T++,res);
     }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值