2019牛客暑期多校训练营(第三场)D.Big Integer(费马小定理+找循环节)
程序员文章站
2022-04-01 15:33:26
...
题意
已知序列为,求
思路
易知,那么有
考虑和的关系,先考虑和互质,那么可以变为
由于互质,所以只有
即
根据费马小定理,和互质有
由于,那么循环节至少为,考虑是否有更小的循环节,根据同余式的性质
那么令为的因子,即,最小的循环节可能为
所以我们可以对的因子进行检验得到最小的循环节,找到了最小的循环节之后我们如何求解答案呢。由于循环节为,所以必须是的倍数。考虑是固定的,那么只要含有的因子就可以了,令,那么中是的倍数的个数为。再考虑,我们可以将唯一分解了,那么就有
就有
随着的变化,的值也是变化的,设,当的值为时也就是随着变化的,我们分别计算每一个的贡献为,当时将不再变化贡献就为
这样就能统计出答案了,但是当时,虽然和互质但是,所以明显的答案都为
第二我们考虑的情况,由于于分母并不互质,所以我们并不能像上面那么做。考虑
由于为长度为连续的的整数,一个整数是否能被整除我们知道就是把各位上的数字加起来是的倍数就能整除了,令每一位上的和为,那么每一位上的和就为,由于上的每一位都是,所以,故最后的答案就是
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
long long quickmod(long long a,long long b,long long mod=1e9+7)
{
long long ans=1;
while(b)
{
if(b%2==1)
ans=ans*a%mod;
b=b/2;
a=a*a%mod;
}
return ans;
}
pair<int,int>a[1005];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
long long p,n,m;
scanf("%lld%lld%lld",&p,&n,&m);
if(p==2||p==5)
{
printf("0\n");
continue;
}
else if(p==3)
{
printf("%lld\n",n/3*m);
continue;
}
long long x=p-1;
int minn=p-1;
for(int i=2; i*i<=x; i++)
{
if(x%i==0)
{
if(quickmod(10,i,p)==1)
minn=min(minn,i);
if(quickmod(10,x/i,p)==1)
minn=min(1ll*minn,x/i);
}
}
int cnt=0;
int maxn=0;
x=minn;
for(int i=2; i*i<=x; i++)
{
if(x%i==0)
{
a[cnt].first=0;
a[cnt].second=0;
a[cnt].first=i;
while(x%i==0)
{
a[cnt].second++;
x=x/i;
}
maxn=max(a[cnt].second,maxn);
cnt++;
}
}
if(x>1)
{
a[cnt].first=0;
a[cnt].second=0;
a[cnt].first=x;
a[cnt].second++;
maxn=max(a[cnt].second,maxn);
cnt++;
}
long long ans=0;
long long g=1;
for(int j=1; j<=min(1ll*maxn,m); j++)
{
g=1;
for(int i=0; i<cnt; i++)
{
g=g*quickmod(a[i].first,ceil(1.0*a[i].second/j));
}
ans+=n/g;
}
if(m>maxn)
ans+=n/g*(m-maxn);
printf("%lld\n",ans);
}
return 0;
}