poj3696 The Luckiest number(质数,欧拉函数)

poj

题意:给定一个正整数L(\(L<=2*10^9\)),求至少多少个8连在一起组成的正整数是L的倍数?

分析:x个8连在一起的正整数可写作\(8*(10^x-1)/9\),于是题目转换为了求一个最小的x,使得\(L|8*(10^x-1)/9\),整理一下式子得\(9*L|8*(10^x-1)\),设\(d=gcd(9*L,8)\).

所以有\(9L/d\)与8/d互质,所以式子等价于\((9L/d)|10^x-1\),所以\(10^x≡1(mod(9L/d))\)

若正整数a,n互质,则满足\(a^x≡1(mod(m))\)的最小正整数\(x\)\(phi(n)\)的约数.(证明略)

所以我们可以求出\(phi(9L/d)\),枚举它的所有约数,用快速幂判断是否满足条件.

#include<iostream>
#include<cstdio>
#include<cmath>
#define ll long long
using namespace std;
ll gcd(ll a,ll b){
    if(b==0)return a;
    return gcd(b,a%b);
}
ll quickmul(ll a,ll b,ll c){
    ll cnt=0;
    while(b){
		if(b&1)cnt=(cnt+a)%c;
		a=(a+a)%c;
		b>>=1;
    }
    return cnt;
}//快速乘,好像没什么必要
ll power(ll a,ll b,ll c){
    ll cnt=1;
    while(b){
		if(b&1)cnt=quickmul(cnt,a,c)%c;
		a=quickmul(a,a,c)%c;
		b>>=1;
    }
    return cnt;
}
ll get_phi(ll n){
    ll cnt=n;
    for(ll i=2;i*i<=n;++i){
		if(n%i==0)cnt=cnt/i*(i-1);
		while(n%i==0)n/=i;
    }
    if(n!=1)cnt=cnt/n*(n-1);
    return cnt;
}
int main(){
    ll L,T=0;
    while(scanf("%lld",&L)&&L!=0){	
		++T;
		ll n=9*L/gcd(1ll*8,1ll*9*L);ll x=get_phi(n);
		if(gcd(10,n)!=1){printf("Case %d: 0\n",T);continue;}
		int bj=0;
		for(ll i=1;i*i<=x;i++)
	    	if(x%i==0&&power(10,i,n)==1){
				printf("Case %lld: %lld\n",T,i);
				bj=1;break;
	    }
		if(bj)continue;
		for(ll i=sqrt(1.0*x);i>=1;i--)
	    	if(x%i==0&&power(10,x/i,n)==1){
				printf("Case %lld: %lld\n",T,x/i);
				break;
	    	}
    }
    return 0;
}

posted on 2019-03-09 13:17  PPXppx  阅读(164)  评论(0编辑  收藏  举报