【欧拉】nkoj3685--8数

给定一个正整数N,判断是否存在一个由全部由数字8组成的N的倍数M,输出最小的这样的M及其8的个数。通过数学运算和欧拉函数解决此问题。

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

P3685  8数
时间限制 : - MS   空间限制 : 65536 KB 评测说明 : 时限:1000ms
问题描述

给一个正整数N,问是否存在N的倍数M,且M的各个位全部由数字8组成,如果存在多个取最小的M

并输出M由几个8组成。

输入格式

一行,一个整数N

输出格式

一行一个整数,表示所求的结果。
如果无解,输出0

样例输入 1

8

样例输出 1

1

样例输入 2

11

样例输出 2

2

样例输入 3

16

样例输出 3

0

样例输入 4

18

样例输出 4

9


















思路:根据题意,求t*n=8...8(k个8)的最小k.
8....8(k个8)=8/9*(10^k-1).
t*n=8/9*(10^k-1).
8/9*(10^k-1)≡ 0 (mod n)
8*(10^k-1)=9*n*t
此时求出8和9*n的最大公约数
d=gcd(8,9*n);
式子可以化简为 8/d*(10^k-1)=(9*n)/d*t
令p=8/d q=9*n/d
那么式子可化为 p*(10^k-1)=q*t
因为p,q为8/d和(9*n)/d,d又是最大公约数,所以p,q一定互质
而式子左右又相等,那么q|(10^k-1)

即 (10^k-1) ≡ 0 (mod q)
10^k≡ 1 (mod q)
欧拉定理a^phi(q)≡ 1(mod q)(其中gcd(a,q)==1)
所以如果10与q不互质,那么一定无解
由幂的周期性得:10^(k*t+r)≡ 1 (mod q)
又因为10^0≡ 1 (mod q)
故r==0
10^(k*t)≡ 1 (mod q)
又因为a^phi(q)≡ 1(mod q)是一组解
所以k*t==phi(q)
枚举phi(q)的因数,找出符合10^(s)≡ 1 (mod q)的最小的s即可
(其中s为phi(q)的因数)

注意:nkoj要用快速乘法
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define inf 1000000000000000000LL
using namespace std;
long long q;
long long ksc(long long x,long long y,long long N){
	long long ans;
	for(ans=0;y;x=(x<<1)%N,y=(y>>1))
	  if(y&1)ans=(ans+x)%N;
	return ans;
}
long long gcd(long long a,long long b){
	if(b==0)return a;
	else return gcd(b,a%b);
}
long long mont(long long a,long long b,long long c){
      long long ans=1;
      a=a%c;
      while(b>0){                       
            if(b&1)ans=ksc(ans,a,c);          
            b=b>>1;                             
            a=ksc(a,a,c);
      }
      return ans;
}
long long phi(long long x){
	long long i,ans=x,a=x;
	for(i=2;i*i<=a;i++){
		if(a%i==0){
			ans=ans-ans/i;
			while(a%i==0)a/=i;
		}
	}
	if(a>1)ans=ans-ans/a;
	return ans;
}
bool check(long long x){
	if(mont(10,x,q)==1)return true;
	else return false;
}
int main(){
	long long d,p,n,i,j,fi,m,minn;
	cin>>n;
	if(n==1||n==2||n==4||n==8){
		cout<<"1";return 0;
	}
	d=gcd(8,9*n);
	p=8/d;
	q=9*n/d;
	fi=phi(q);
	//cout<<fi<<endl;
	if(gcd(10,q)!=1){
		cout<<"0";return 0;
	}
	m=floor(sqrt(fi)+0.5);
	minn=fi;
	for(i=2;i<=m;i++){
		if(fi%i==0){
			if(check(i)){
				cout<<i;
				return 0;
			}
			if(check(fi/i)){
				minn=min(minn,fi/i);
			}
		}
	}
	cout<<minn;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值