链接:http://acm.hdu.edu.cn/showproblem.php?pid=5393
题意:给出
k,b,x0,p
,
xn=(xn−1∗k+b)modp
,求最小的n,使得
xn=x0
,如果不存在输出-1。
分析:通过简单的数学推导,题目即求最小的n使得
((k−1)∗x0+b)∗(1+k+k2+k3+...kn−1)≡0modp
根据同余的性质,
(a∗g)mod(b∗g)
等价于
amodb
,于是可以消去
gcd(p,(k−1)∗x0+b)
,剩下的就是求最小的n使得
1+k+k2+k3+...kn−1≡0modq
两边同乘
k−1
,由于
k−1
不一定与q互质,因此由此推出来的式子只是原式的必要条件,我们得到
kn≡1modq
假如k,q不互质,上式恒不成立,原式无解,否则根据欧拉定理,有
kΦ(q)≡1modq
我们只需要检查
Phi(q)的约数,得到最小的n满足条件。
假设真实的答案为ans,根据前面的推导,ans必然为n的倍数,设 ans=g∗n 则
1+k+k2+k3+...kans−1≡g∗(1+k+k2+k3+...kn−1)modq
因此只需要把n带回去,然后求lcm即可,注意带回去算答案可以只用一个log的复杂度,总复杂度就是分解约数的复杂度*powmod的复杂度,大概是
log2p
#include<bits/stdc++.h>
using namespace std;
typedef long long Int;
int getphi(int x)
{
int ret=1;
for(int i=2;i*(Int)i<=x;i++)
if(x%i==0)
{
ret=ret*(i-1);
x/=i;
while(x%i==0)x/=i,ret*=i;
}
if(x>1)ret=ret*(x-1);
return ret;
}
int powmod(int x,int y,int mod)
{
int ret=1;
while(y){if(y&1)ret=ret*(Int)x%mod;y>>=1;x=x*(Int)x%mod;}
return ret;
}
int check(int x,int y,int mod)
{
vector<int>V;
while(y){V.push_back(y&1);y>>=1;}
reverse(V.begin(),V.end());
int ret=0,tp=1;
for(int i=0;i<V.size();i++)
{
ret=(ret+ret*(Int)tp%mod)%mod;
tp=tp*(Int)tp%mod;
if(V[i])
{
tp=tp*(Int)x%mod;
ret=(ret+tp)%mod;
}
}
return (ret+1)%mod;
}
int main()
{
int _;scanf("%d",&_);
while(_--)
{
int k,b,x,p;
scanf("%d%d%d%d",&k,&b,&x,&p);
if(!k){puts(b==x?"1":"-1");continue;}
if(k==1)
{
if(!b)puts("1");
else
{
printf("%d\n",p/__gcd(b,p));
}
continue;
}
int q=p/__gcd((Int)p,(Int)(k-1)*x+b);
if(q==1){puts("1");continue;}
if(__gcd(k,q)!=1){puts("-1");continue;}
int t=getphi(q);
int rep=t;
for(int i=1;i*(Int)i<=t;i++)
{
if(t%i==0)
{
if(powmod(k,i,q)==1){rep=i;break;}
if(powmod(k,t/i,q)==1)rep=t/i;
}
}
int ans=check(k,rep-1,q);
if(!ans){printf("%d\n",rep);continue;}
printf("%lld\n",q/__gcd(ans,q)*(Int)rep);
}
}