比较巧妙的题
前置知识点
欧拉函数
中国剩余定理
题目描述
求在\([1,x]\)中有多少\(n\),满足:
\(n\cdot a^n≡b\pmod p\)
输入格式
一行四个数分别表述\(a,b,p,x\)
输出格式
一行一个数表述答案
数据范围
\(1≤x≤10^{12},1≤a,b,p≤10^9,保证p与a互质\)
题面基础,数据范围就不基础(不是)
显然我们需要慢慢思考
最简单的想法肯定是暴力找\([1,x]\)的所有数进行判断,但这显然会超
聪明的你肯定想到,既然\(a,p\)互质,那么\(a^{\varphi(p)}\equiv1\pmod p\),所以\(n\cdot a^n\)在模\(p\)意义下以\({lcm}(p,\varphi(p))\)为一个周期循环,那么我们只需要遍历\({lcm}(p,\varphi(p))\)以内的\(x\)就好了。
然而这还是很大的范围啊…
我们又注意到,\(a^n与n\)的周期都要短的多,而且之后的值我们确实都分别算过了
于是我们可以遍历\(i\in [1,\varphi(p)]\)的所有数,假如此时存在\(n\)满足条件,则有
\(\left\{\begin{matrix}
n\equiv i\pmod{\varphi(p)}\\
n\equiv a^{-i}b\pmod p
\end{matrix}\right.\)
可以使用EXCRT求解该方程组,最后统计答案即可
点击查看代码
#include<bits/stdc++.h>
using namespace std;
long long a,b,x,p,t,phi,inv,lcm,ans,mi,k1,_k2,gcd;
queue <long long> q;
void getphi(long long n,long long &a)
{
a=1;
for(long long i=2;i*i<=n;i++)
{
if(n%i)
continue;
a*=i-1,n/=i;
while(n%i==0)
n/=i,a*=i;
}
if(n>1)
a*=n-1;
}
long long exgcd(long long a,long long &x,long long b,long long &y)
{
if(!b)
{
x=1,y=0;
return a;
}
long long d=exgcd(b,y,a%b,x);
y=y-a/b*x;
return d;
}
//long long mul(long long a,long long b,long long p)
//{
// long long s=0,f=a<0?-1:1;
// a*=f;
// for(;b;b>>=1,a=a<<1,a-=a>=p?p:0)
// if(b&1)
// s=s+a,s-=s>=p?p:0;
// return s*f;
//}
int main()
{
scanf("%lld %lld %lld %lld",&a,&b,&p,&x);
a%=p,t=b%=p;
getphi(p,phi);
exgcd(a,inv,p,k1);
gcd=exgcd(phi,k1,p,_k2);
lcm=p/gcd*phi;
for(long long i=1;i<=x&&i<=phi;++i)
{
t=t*inv%p;
if((t-i)%gcd)
continue;
long long an;
an=(t-i)/gcd*k1%lcm*phi%lcm+i;
if(an<0)
an+=lcm;
if(an>=lcm)
an-=lcm;
if(an<=x)
ans+=(x-an)/lcm+1;
}
printf("%lld\n",ans);
return 0;
}
浙公网安备 33010602011771号