牛客多校第三场 D Big Integer(欧拉函数&计数)
题目大意
给出一个函数 A ( n ) = ∑ i = 0 n − 1 1 0 i A(n)=\sum_{i=0}^{n-1}10^i A(n)=∑i=0n−110i,现在给出一个素数p,以及范围n,m.求有多少 ( i , j ) (i,j) (i,j)满足 1 ≤ i ≤ n , 1 ≤ j ≤ m , A ( i j ) ≡ 0 ( m o d p ) 1\le i\le n,1\le j\le m,A(i^j)\equiv0(mod\ p) 1≤i≤n,1≤j≤m,A(ij)≡0(mod p)
解题思路
看到1111111…很容易想到POJ的那个‘The Luckiest number’即将’111111…'写成
1
0
n
−
1
9
\frac{10^n-1}{9}
910n−1
那么原式就可以化成
1
0
n
≡
1
(
m
o
d
9
p
)
10^n\equiv 1(mod\ 9p)
10n≡1(mod 9p)
那么通过枚举
φ
(
9
p
)
\varphi(9p)
φ(9p)的因数就可以得到满足这个条件的循环节,设为g
那么只要满足 g ∣ i j g|i^j g∣ij就是满足条件的(i,j)
首先对g进行因式分解
g
=
p
1
b
1
p
2
b
2
.
.
.
p
n
n
n
g=p_1^{b_1}p_2^{b_2}...p_n^{n_n}
g=p1b1p2b2...pnnn
确定一个j之后则i必须要是
d = p 1 ⌈ b 1 j ⌉ p 2 ⌈ b 2 j ⌉ . . . p n ⌈ b n j ⌉ d=p_1^{\left\lceil\frac{b_1}{j}\right\rceil}p_2^{\left\lceil\frac{b_2}{j}\right\rceil}...p_n^{\left\lceil\frac{b_n}{j}\right\rceil} d=p1⌈jb1⌉p2⌈jb2⌉...pn⌈jbn⌉
的倍数,因此共有 ⌊ n d ⌋ \left\lfloor {n\over d}\right\rfloor ⌊dn⌋各合法答案
可以发现g的所有质因子的次数都不会超过30,因此j最大到30,再增大则不会对d造成影响故直接相加即可
AC代码
#include<bits/stdc++.h>
using namespace std;
typedef __int128 LL;
LL quick_pow(LL a,LL b,LL mod)
{
LL ans=1;
a=a%mod;
while(b)
{
if(b&1) ans=ans*a%mod;
a=1LL*a*a%mod;
b>>=1;
}
return ans;
}
LL pows(long long f,int s,int m)
{
LL ans=1;
int tims=s/m+(s%m!=0);
while(tims)
{
if(tims&1) ans=ans*f;
f=f*f;
tims>>=1;
}
return ans;
}
vector<LL> fac;
int cnt[50];
int tor[50],tot;
int main()
{
int t;
scanf("%d",&t);
int p,n,m;
while(t--)
{
scanf("%d%d%d",&p,&n,&m);
if(p%2==0||p%5==0)
{
puts("0");
continue;
}
LL phi=6LL*(p-1);
if(p==3) phi=18;
LL mod=9LL*p;
fac.clear();
for(LL i=1;i*i<=phi;i++)
{
if(phi%i!=0) continue;
fac.push_back(i);
fac.push_back(phi/i);
}
sort(fac.begin(),fac.end());
LL g=phi;
for(auto x:fac)
{
if(quick_pow(10,x,mod)==1) {g=x;break;}
}
LL tmp=g;
tot=0;
for(LL i=2;i*i<=tmp;i++)
{
if(g%i==0)
{
tor[++tot]=i;cnt[tot]=0;
do g/=i,cnt[tot]++;
while(g%i==0) ;
}
}
if(g>1) {tor[++tot]=g;cnt[tot]=1;}
g=tmp;
int mx=0;
for(int i=1;i<=tot;i++) mx=max(mx,cnt[i]);
LL tg=1;
long long ans=0;
for(LL i=1;i<=min(mx,m);i++)
{
tg=1;
for(int j=1;j<=tot;j++) tg=tg*pows(tor[j],cnt[j],i);
ans=ans+n/tg;
}
ans=ans+max(0,(m-mx))*(n/tg);
printf("%lld\n",ans);
}
}