51Nod1037 最长的循环节 V2

这篇博客探讨了如何求解最长循环节的问题,通过数学分析将循环小数转化为分数形式,并利用欧拉定理和数论方法寻找满足条件的最大k。文章介绍了Miller-Rabin和Pollard Rho算法在分解质因数和求phi函数中的应用,最终实现从n开始向下枚举以找到答案。代码示例中展示了如何运用这些算法来解决此类问题。

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


题目看这里
小学奥数题目23333
首先我们知道, 0.0˙0...001˙=1/99..9 0. 0 ˙ 0...00 1 ˙ = 1 / 99..9
那么任意一个循环小数都可以写成以 10k1 10 k − 1 为分母的分数
让后稍加分析就知道,满足条件的最小的k就是循环节的长度
那么题目就变成了求一个数s,使得满足 10k=1 ( mod s ) 10 k = 1   (   m o d   s   ) 这样的k最大
我们将k记为 f(s) f ( s )
首先由欧拉定理得 10ϕ(s)=1(mod s) 10 ϕ ( s ) = 1 ( m o d   s ) 所以 f(s)|ϕ(s) f ( s ) | ϕ ( s )
让后再根据打表的规律,我们发现满足条件的数其实非常多(密度>0.5)
所以我们可以猜测,只有当 f(s)=ϕ(s) f ( s ) = ϕ ( s ) 时才能取到最多(否则 2f(s)<=ϕ(s) 2 f ( s ) <= ϕ ( s )
于是我们采用 Miller Rabin+Pollard Rho M i l l e r   R a b i n + P o l l a r d   R h o 来分解质因数求 ϕ ϕ ,从n开始向 下枚举即可,由于密度很高,所以很快就可以得到答案

#pragma GCC opitmize("O3") # p r a g m a   G C C   o p i t m i z e ( " O 3 " )
#pragma G++ opitmize("O3") # p r a g m a   G + +   o p i t m i z e ( " O 3 " )
#include<time.h> # i n c l u d e < t i m e . h >
#include<vector> # i n c l u d e < v e c t o r >
#include<stdio.h> # i n c l u d e < s t d i o . h >
#include<string.h> # i n c l u d e < s t r i n g . h >
#include<algorithm> # i n c l u d e < a l g o r i t h m >
#define LL long long # d e f i n e   L L   l o n g   l o n g
using namespace std; u s i n g   n a m e s p a c e   s t d ;
vector<LL> s,t,w; v e c t o r < L L >   s , t , w ;
inline LL mul(LL x,LL k,LL M,LL s=0){ i n l i n e   L L   m u l ( L L   x , L L   k , L L   M , L L   s = 0 ) {
for(;k;x=(x+x)%M,k>>=1) k&1?s=(s+x)%M:0; f o r ( ; k ; x = ( x + x ) % M , k >>= 1 )   k & 1 ? s = ( s + x ) % M : 0 ;
return s; r e t u r n   s ;
} }
inline LL pow(LL x,LL k,LL M,LL s=1){ i n l i n e   L L   p o w ( L L   x , L L   k , L L   M , L L   s = 1 ) {
for(;k;x=mul(x,x,M),k>>=1) k&1?s=mul(s,x,M):0; f o r ( ; k ; x = m u l ( x , x , M ) , k >>= 1 )   k & 1 ? s = m u l ( s , x , M ) : 0 ;
return s; r e t u r n   s ;
} }
inline bool test(LL n,LL a,LL d){ i n l i n e   b o o l   t e s t ( L L   n , L L   a , L L   d ) {
if(n==2 || n==a) return 1; i f ( n == 2   | |   n == a )   r e t u r n   1 ;
if( n&1) return 0; i f (   n & 1 )   r e t u r n   0 ;
while( d&1) d>>=1; w h i l e (   d & 1 )   d >>= 1 ;
LL t=pow(a,d,n); L L   t = p o w ( a , d , n ) ;
while((d!=n1)&&(t!=1)&&(t!=n1)){ w h i l e ( ( d ! = n − 1 ) & & ( t ! = 1 ) & & ( t ! = n − 1 ) ) {
t=mul(t,t,n); t = m u l ( t , t , n ) ;
d<<=1; d <<= 1 ;
} }
return (t==n1 || d&1); r e t u r n   ( t == n − 1   | |   d & 1 ) ;
} }
inline bool prime(LL n){ i n l i n e   b o o l   p r i m e ( L L   n ) {
if(n<2) return 0; i f ( n < 2 )   r e t u r n   0 ;
int a[6]={2,61,3,40357,49919,19260817}; i n t   a [ 6 ] = { 2 , 61 , 3 , 40357 , 49919 , 19260817 } ;
for(int i=0;i<5;++i) f o r ( i n t   i = 0 ; i < 5 ; + + i )
if(!test(n,a[i],n1)) return 0; i f ( ! t e s t ( n , a [ i ] , n − 1 ) )   r e t u r n   0 ;
return 1; r e t u r n   1 ;
} }
inline LL gcd(LL a,LL b){ i n l i n e   L L   g c d ( L L   a , L L   b ) {
for(LL c;b;a=b,b=c) c=a%b; f o r ( L L   c ; b ; a = b , b = c )   c = a % b ;
return a; r e t u r n   a ;
} }
inline LL rho(LL n){ i n l i n e   L L   r h o ( L L   n ) {
begin: b e g i n :
LL c=rand()%n; int i=1,k=2; L L   c = r a n d ( ) % n ;   i n t   i = 1 , k = 2 ;
LL x=rand()%n+1,y=x,d; L L   x = r a n d ( ) % n + 1 , y = x , d ;
for(;;){ f o r ( ; ; ) {
i++; i + + ;
x=(mul(x,x,n)+c)%n; x = ( m u l ( x , x , n ) + c ) % n ;
d=gcd(xy,n); d = g c d ( x − y , n ) ;
if(1<d && d<n) return d; i f ( 1 < d   & &   d < n )   r e t u r n   d ;
if(y==x) goto begin; i f ( y == x )   g o t o   b e g i n ;
if(i==k){ y=x; k<<=1; } i f ( i == k ) {   y = x ;   k <<= 1 ;   }
} }
} }
inline LL read(){ i n l i n e   L L   r e a d ( ) {
LL x=0; char c=getchar(); L L   x = 0 ;   c h a r   c = g e t c h a r ( ) ;
while(c>9 || c<0) c=getchar(); w h i l e ( c > ′ 9 ′   | |   c < ′ 0 ′ )   c = g e t c h a r ( ) ;
while(c>=0&&c<=9){ x=(x<<3)+(x<<1)+(c48);c=getchar(); } w h i l e ( c > = ′ 0 ′ & & c < = ′ 9 ′ ) {   x = ( x << 3 ) + ( x << 1 ) + ( c − 48 ) ; c = g e t c h a r ( ) ;   }
return x; r e t u r n   x ;
} }
LL n; L L   n ;
inline void dfs(LL x){ i n l i n e   v o i d   d f s ( L L   x ) {
if(prime(x)){ s.push_back(x); return; }  i f ( p r i m e ( x ) ) {   s . p u s h _ b a c k ( x ) ;   r e t u r n ;   }  
LL y=rho(x); while(x%y==0) x/=y; L L   y = r h o ( x ) ;   w h i l e ( x % y == 0 )   x / = y ;
if(x>1) dfs(x); dfs(y); i f ( x > 1 )   d f s ( x ) ;   d f s ( y ) ;
} }
inline void dt(LL x,int i){ i n l i n e   v o i d   d t ( L L   x , i n t   i ) {
if(i==s.size()){ w.push_back(x); return; } i f ( i == s . s i z e ( ) ) {   w . p u s h _ b a c k ( x ) ;   r e t u r n ;   }
for(int j=0;j<=t[i];++j) dt(x,i+1),x=s[i]; f o r ( i n t   j = 0 ; j <= t [ i ] ; + + j )   d t ( x , i + 1 ) , x ∗ = s [ i ] ;
} }
int d(LL n){ i n t   d ( L L   n ) {
if(!prime(n)) return 0; LL m=n1; i f ( ! p r i m e ( n ) )   r e t u r n   0 ;   L L   m = n − 1 ;
s.clear(); t.clear(); w.clear(); dfs(n1);  s . c l e a r ( ) ;   t . c l e a r ( ) ;   w . c l e a r ( ) ;   d f s ( n − 1 ) ;  
for(int i=0;i<s.size();++i)  f o r ( i n t   i = 0 ; i < s . s i z e ( ) ; + + i )  
for(t.push_back(0);m%s[i]==0;m/=s[i]) ++t[i]; f o r ( t . p u s h _ b a c k ( 0 ) ; m % s [ i ] == 0 ; m / = s [ i ] )   + + t [ i ] ;
dt(1,0); d t ( 1 , 0 ) ;
sort(w.begin(),w.end()); s o r t ( w . b e g i n ( ) , w . e n d ( ) ) ;
for(int i=0;i<w.size();++i)  f o r ( i n t   i = 0 ; i < w . s i z e ( ) ; + + i )  
if(pow(10,w[i],n)==1){ i f ( p o w ( 10 , w [ i ] , n ) == 1 ) {
if(w[i]==n1){ printf("%lld\n",n); exit( 0 ); } i f ( w [ i ] == n − 1 ) {   p r i n t f ( " % l l d \n " , n ) ;   e x i t (   0   ) ;   }
else return 0; e l s e   r e t u r n   0 ;
} }
} }
int main(){ i n t   m a i n ( ) {
n=read(); n = r e a d ( ) ;
while(!d(n)) n; w h i l e ( ! d ( n ) )   n − − ;
} }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值