循環節的定義
如果無限小數的小數點後,從某一位起向右進行到某一位止的一節數字循環出現,首尾銜接,稱這種小數爲循環小數,這一節數字稱爲循環節。
研究背景
給定一個整數,求最小的使 ( )。此時的就等價於的循環節的長度。
引理:對於 ( ),若與互質,那麼最小的必定是的約數;若與有公因子,顯然無解。
根據這個性質,只要枚舉的每個約數分別驗證,就能求出循環節的最小長度了。
例題:Big Integer
鏈接
題意
給定。表示一個由個組成的數。
求有多少對,滿足,,使得 。
分析
11…111 = ≡ 0 (mod p)
等價於
當的倍數的時候,有,因此
我們需要找到滿足 的最小循環節長度。
根據前面說到的性質,必定是的約數,
暴力枚舉的約數分別驗證就能找到最小循環節。
由於的倍數都可能作爲循環節,所以接下來我們要找到有多少對,滿足 | 。
將進行質因子分解,得到,
考慮當固定時,必須是的倍數。
因此一共有個合法的。
由於所有,所以當時,,
因此只需計算從到的的值即可。
當的倍數時,顯然答案爲。
代碼
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
template<class T>inline void MAX(T &x,T y){if(y>x)x=y;}
template<class T>inline void MIN(T &x,T y){if(y<x)x=y;}
template<class T>inline void rd(T &x){
x=0;char o,f=1;
while(o=getchar(),o<48)if(o==45)f=-f;
do x=(x<<3)+(x<<1)+(o^48);
while(o=getchar(),o>47);
x*=f;
}
const int M=1e5+5;
int cas,cnt[M],mark[M];
ll n,m,p,prime[M];
ll Fast(ll a,ll b,ll P){
ll res=0;
while(b){
if(b&1)res=(res+a)%P;
a=(a+a)%P;
b>>=1;
}
return res;
}
ll fast(ll a,ll b,ll P){
ll res=1;
while(b){
if(b&1)res=Fast(res,a,P);
a=Fast(a,a,P);
b>>=1;
}
return res;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("jiedai.in","r",stdin);
// freopen("jiedai.out","w",stdout);
#endif
for(ll i=2;i<M;i++)if(!mark[i])
for(ll j=i*i;j<M;j+=i)mark[j]=1;
rd(cas);
while(cas--){
rd(p),rd(n),rd(m);
if(p%2==0||p%5==0){puts("0");continue;}
ll P=9*p,phi=1,tmp=P;
for(ll i=2;i*i<=P;i++){
if(!mark[i]){
int tp=1;
while(tmp%i==0){
tmp/=i;
if(tp)phi*=i-1,tp=0;
else phi*=i;
}
}
}
if(tmp>1)phi*=tmp-1;
ll d=phi,res=0,ans=0;
for(ll i=1;i*i<=phi;i++)
if(phi%i==0&&fast(10,i,P)==1)
{MIN(d,i);break;}
for(ll i=sqrt(phi);i;i--)
if(phi%i==0&&fast(10,phi/i,P)==1)
{MIN(d,phi/i);break;}
tmp=d;
for(ll i=2;i*i<=d;i++)if(!mark[i]&&d%i==0){
prime[++res]=i;
cnt[res]=0;
while(tmp%i==0)cnt[res]++,tmp/=i;
}
if(tmp>1)prime[++res]=tmp,cnt[res]=1;
for(int j=1;j<=min(30ll,m);j++){
tmp=1;
for(int i=1;i<=res;i++)
for(int t=1;t<=(cnt[i]+j-1)/j;t++)
tmp*=prime[i];
ans+=n/tmp;
if(j==30)ans+=(n/tmp)*(m-30);
}
printf("%lld\n",ans);
}
return (0-0);
}