POJ 3696 神TM数论

本文解析了一道关于寻找最短8的倍数能够整除特定数值的数论难题,通过数论变换将问题转化为求模意义下的指数问题,并利用欧拉定理及原根理论进行解答。

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

鸣谢:
http://blog.youkuaiyun.com/yhrun/article/details/6908470
http://blog.sina.com.cn/s/blog_6a46cc3f0100tvqg.html

题意:链接君已失效

方法:各种数论

解析:老师找了两道数论题,这是第一道,听说比第二道简单多了,然而我并不会,看题解也是好顿理解,这题太值得做了!不做悔一生!

咳,回归正题,这道题就是一个神奇的数,问你最短需要多少个8组成的数能整除他?所以你有思路么?并没有!有思路你也不会来看我唠叨了!所以接下来,请你清理下脑子,来看我论证。

首先呢我们可以这么理解

8(10x1)/9=kL 其中k为常数

然后呢因为这个9在分母上,如果涉及取余或者什么东西的话会很麻烦,所以我们把它乘到右边,然后会变成什么呢?

8(10x1)=9kL (我知道以上都是废话)

再进一步 8(10x1)/gcd(8,L)=9kL/gcd(8,L)

接下来便于计算

我们令 p=8/gcd(8,L),q=9L/gcd(8,L)

所以原式变为 (10x1)p=kq

因为p与q是互质的,这就是为什么我除了个最大公约数。

所以 (10x1)

10x1(modq)

又根据欧拉定理

gcd(a,b)==1 可得到 aφ(b)1(modb)

所以 10φ(q)1(modq)

之后呢又有这么个结论,最小的解为 φ(q) 的因子,这个呢是原根的某个定理的推论,简单说明一下原因呢是这样的

设k不是φ(n)的约数

10k1(modn)

假设gcd(k,φ(n))=s,必然有一个数a,a是k的倍数,a+s是φ(n)的倍数。

10a10k1(modn)

10(a+s)10φ(n)1(modn)

10s1(modn)

而k不是φ(n)的约数,s是φ(n)的约数,s又是k的约数

所以s<k。而若k是符合要求的,则必然有一个更小的s。

所以答案一定是φ(n)的约数。

之后就乱搞吧!

友情提示!

欧拉可能算爆long long

所以最好把9单独讨论!

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100100
using namespace std;
typedef long long ll;
ll prime[N];
ll ans[2*N];
int hash[N];
int tot;
ll q;
void quick_pri()
{
    for(int i=2;i<=100000;i++)
    {
        if(!hash[i])prime[++tot]=i;
        for(int j=1;j<=tot&&prime[j]*i<=100000;j++)
        {
            hash[prime[j]*i]=1;
            if(i%prime[j]==0)break;
        }
    }
}
ll mul(ll a,ll b)
{
    ll ret=0;
    while(b)
    {
        if(b&1)ret=(ret+a)%q;
        a=(a+a)%q,b>>=1;
    }
    return ret;
}
ll quick_my(ll a,ll b)
{
    ll ret=1;
    while(b)
    {
        if(b&1)ret=mul(ret,a);
        a=mul(a,a),b>>=1;
    }
    return ret;
}
ll gcd(ll a,ll b)
{
    while(b)
    {
        ll t=b;
        b=a%b;
        a=t;
    }
    return a;
}
ll phi(ll a)
{
    ll ans=a;
    for(int i=1;prime[i]*prime[i]<=a;i++)
    {
        if(a%prime[i]==0)ans=(ans/prime[i])*(prime[i]-1);
        while(a%prime[i]==0)a/=prime[i];
    }
    if(a!=1)ans=ans*(a-1)/a;
    return ans;
}
int main()
{
    quick_pri();
    ll n;
    int casecnt=0;
    while(scanf("%lld",&n)&&n!=0)
    {
        tot=0;
        printf("Case %d: ",++casecnt);
        q=n/gcd(8,n);
        if(gcd(10,9*q)!=1){printf("0\n");continue;}
        else
        {
            ll tmp=phi(q);
            if(q%3!=0)tmp*=6;
            else tmp*=9;
            q*=9;
            for(ll i=1;i*i<=tmp;i++)
            {
                if(tmp%i==0)ans[++tot]=i,ans[++tot]=tmp/i;
            }
            sort(ans+1,ans+1+tot);
            int flag=0;
            for(int i=1;i<=tot;i++)
            {
                if(quick_my(10,ans[i])==1){printf("%lld\n",ans[i]);flag=1;break;}
            }
            if(!flag)printf("0\n");
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值