【POJ3696】The Luckiest Number-欧拉定理+快速幂

测试地址:The Luckiest Number
题目大意:给出一个正整数L(2,000,000,000),要使正整数888...8K能整除L,求最小的K,如果不存在这样的K则输出0。
做法:这题的思路很神……没看题解的时候根本不知道怎么做,调也调了好一会,我好弱啊……
这一题需要使用欧拉定理+快速幂来解决。
我们发现999...9K可以表示为10K1,所以888...8K可以表示为8/9×(10K1),那么存在一个整数p使得8/9×(10K1)=L×p,所以10K1=9/8×L×p。由于等式右边要是整数,那么p应该满足8|(L×p)。因为L已经包含gcd(L,8)这些因子,所以p需要包含8/gcd(L,8)这些因子,所以可以将p写成p=8/gcd(L,8)×p1。将其代入前面的式子,可以得到10K1=9×L/gcd(L,8)×p1,设m=9×L/gcd(L,8),则原式可以写成10K1=m×p1,这样我们就把问题转化成了求同余方程10K1(modm)的最小的正整数解。根据欧拉定理,可以得到10φ(m)1(modm),可以证明如果K是一个小于φ(m)的解,那么K|φ(m)。那么我们就可以按照下列步骤完成这一题:
1.求出mφ(m)φ(m)的所有质因子。这一步可以用O(N)的试除法来做。
2.令x=φ(m),对于φ(m)的每一个质因子pi,判断10x/pi%m是否等于1,如果等于则令x=x/pi,否则跳过。由于指数很大,需要使用快速幂来算出结果,而因为数字直接乘起来可能会溢出,要用快速乘代替乘法。
3.对所有质因子进行以上操作后,最后的x就是最小的K
那么无解的情况呢?显然可知,如果gcd(10,m)1,那么上面的同余方程就无解。这样我们就完美解决了这一题。
犯二的地方:试除法忘记探测最后剩余是不是1了,导致可能漏掉一个质因子,以后要注意……
以下是本人代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
ll L,fac[1010]={0};

ll gcd(ll a,ll b)
{
  return (b==0)?a:gcd(b,a%b);
}

ll phi(ll x)
{
  ll p=x,s=x;
  for(ll i=2;i*i<=s;i++)
    if (!(x%i))
    {
      p=p/i*(i-1);
      while(!(x%i)) x/=i;
    }
  if (x>1) p=p/x*(x-1);
  return p;
}

void find_factor(ll x)
{
  ll s=x;
  fac[0]=0;
  for(ll i=2;i*i<=s;i++)
    if (!(x%i))
    {
      fac[++fac[0]]=i;
      while(!(x%i)) x/=i;
    }
  if (x>1) fac[++fac[0]]=x;
}

ll mult(ll a,ll b,ll mod)
{
  a%=mod,b%=mod;
  ll s=a,sum=0;
  while(b)
  {
    if (b&1)
    {
      sum+=s;
      if (sum>=mod) sum-=mod;
    }
    b>>=1;
    s<<=1;
    if (s>=mod) s-=mod;
  }
  return sum;
}

ll power(ll a,ll b,ll mod)
{
  ll s=a,sum=1;
  while(b)
  {
    if (b&1) sum=mult(sum,s,mod);
    b>>=1;s=mult(s,s,mod);
  }
  return sum;
}

int main()
{
  int t=0;
  while(scanf("%lld",&L)&&L)
  {
    t++;
    ll m=L/gcd(L,8)*9,p=phi(m),x=p;
    if (gcd(m,10)!=1) {printf("Case %d: 0\n",t);continue;}
    find_factor(p);
    for(int i=1;i<=fac[0];i++)
    {
      while(1)
      {
        x/=fac[i];
        if (power(10,x,m)!=1)
        {
          x*=fac[i];
          break;
        }
        else if (x%fac[i]) break;
      }
    }
    printf("Case %d: %lld\n",t,x);
  }

  return 0;
}
posted @ 2017-05-26 23:58  Maxwei_wzj  阅读(134)  评论(0编辑  收藏  举报