• poj 3696 The Luckiest Number


    The Luckiest Number

        题目大意:给你一个int范围内的正整数n,求这样的最小的x,使得:连续的x个8可以被n整除。

        注释:如果无解输出0。poj多组数据,第i组数据前面加上Case i: 即可。

          想法:这题还是挺好的。我最开始的想法是一定有超级多的数输出0。然后...我就在哪里找啊找....其实这道题是一道比较好玩儿的数论题。我们思考:连续的8可用什么来表示出来?$frac{(10^x-1)}{9}cdot 8$。其实想到这一步这题就做完了。这题的精髓就在于告诉我们连续的连续的一串数的表达方式。想到这点其实有一个比较容易接受的方法:这鬼东西是一个等比数列。然后,式子就可以化成了以下的形式及推导

        $Rightarrow n|frac{10^x-1}{9}cdot 8$

        $Rightarrow 9cdot n|(10^x-1)cdot 8$

        $Rightarrow frac{9cdot n}{gcd(n,8)}|frac{(10^x-1)cdot8}{gcd(n,8)}$

        $ecause gcd(frac n{gcd(n,8)},frac8{gcd(n,8)})=1$

        且$gcd(9,8)=1$

        $ herefore gcd(frac{9cdot n}{gcd(n,8)},frac{8}{gcd(n,8)})=1$

        $Rightarrow frac{9cdot n}{gcd(n,8)}|10^x-1$

        $Rightarrow 10^xequiv1(modfrac{9cdot n}{gcd(n,8)})$

        所以此时,我们只需要枚举mod数即可。但是有些操作是不必要的,在此,我们有两种简单的优化:

        1.对于mod数取$varphi$,然后暴力枚举$varphi$的所有因子。时间复杂度$O(sqrt{n})$,验证是用快速幂,时间复杂度O(logn),所以,总时间复杂$O(sqrt{n}cdot {logn})$。

        2.用BSGS优化,我没想到(鸣谢CQzhangyu)。时间复杂度同理。

        但是对于第一种我们可以用Miller_Rabin 和Pullard_rho进行爆炸般的优化,但是没什么必要......

          最后,附上丑陋的代码......

    #include <iostream>
    #include <cstdio>
    typedef long long ll;
    using namespace std;
    ll gcd(ll a,ll b)//只取一次mod的gcd,鸣谢EdwardFrog
    {
        return b?gcd(b,a%b):a;
    }
    ll quick_multiply(ll a,ll b,ll mod)//快速乘,防止爆longlong,虽然没有必要
    {
        ll ans=0;
        a%=mod;
        b%=mod;
        while(b)
        {
            if(b&1) ans=(ans+a)%mod;
            b>>=1;
            a=(a+a)%mod;
        }
        return ans;
    }
    ll quick_power(ll a,ll b,ll mod)//这题不爆longlong,但是这样是必须的,因为9*n在longlong范围内
    {
        ll ans=1;
        a%=mod;
        while(b)
        {
            if(b&1) ans=quick_multiply(ans,a,mod);
            b>>=1;
            a=quick_multiply(a,a,mod);
        }
        return ans;
    }
    int main()
    {
        ll n;
        ll cnt=0;
        while(1)
        {
            scanf("%lld",&n);
            if(n==0) return 0;
            printf("Case %lld: ",++cnt);
            n=9*n/gcd(n,8);
            ll m=n;
            ll phi=n;
            if(gcd(n,10)!=1)//这是欧拉定理所必须满足的,如果不行显然无解
            {
                printf("0
    ");
                continue;
            }
            for(ll i=2;i*i<=m;++i)
            {
                if(m%i==0)
                {
                    phi=phi/i*(i-1);
                    while(m%i==0)
                    {
                        m/=i;
                    }
                }
            }
            if(m!=1) phi=phi/m*(m-1);
            // cout<<"phi="<<phi<<endl;调试信息
            ll minn=phi;//我想取最小值,且最大值是phi
            for(ll i=1;i*i<=phi;i++)//这步是验证。
            {
                if(phi%i==0)
                {
                    if(quick_power(10,i,n)==1) minn=min(minn,i);
                    if(quick_power(10,phi/i,n)==1) minn=min(minn,phi/i);
                }
            }
            printf("%lld
    ",minn);
        }
    }

        小结:错误,枚举一个数的因子其实是可以根号时间内完成的...我傻逼了......

            还有,别忘记phi开始的初值是n,不是1.

  • 相关阅读:
    LintCode "Maximum Gap"
    LintCode "Wood Cut"
    LintCode "Expression Evaluation"
    LintCode "Find Peak Element II"
    LintCode "Remove Node in Binary Search Tree"
    LintCode "Delete Digits"
    LintCode "Binary Representation"
    LeetCode "Game of Life"
    LintCode "Coins in a Line"
    LintCode "Word Break"
  • 原文地址:https://www.cnblogs.com/ShuraK/p/8179127.html
Copyright © 2020-2023  润新知