zoukankan      html  css  js  c++  java
  • 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.

  • 相关阅读:
    CSS3 渐变 透明 圆角
    使用JSON作为函数的参数(转载)
    如何让输入的单词首字母大写
    mysql 修改表/字段 增加/删除表索引
    Jquery Mobile 客户端验证
    如何写出漂亮的js代码(转载)
    GoogleMap添加一个Marker
    Log4j的使用【转载】
    Google Map 自定义infowindow
    MYSQL重装出现could not start the service mysql error:0处理(已验证可以使用)
  • 原文地址:https://www.cnblogs.com/ShuraK/p/8179127.html
Copyright © 2011-2022 走看看