您的位置:首页 > 其它

hdu5393 Falsyta in Tina Town

2015-08-16 13:31 281 查看
链接:http://acm.hdu.edu.cn/showproblem.php?pid=5393

题意:给出k,b,x0,pk,b,x_0,p,xn=(xn−1∗k+b)modpx_{n}=(x_{n-1}*k+b )\mod p,求最小的n,使得xn=x0x_n=x_0,如果不存在输出-1。

分析:通过简单的数学推导,题目即求最小的n使得

((k−1)∗x0+b)∗(1+k+k2+k3+...kn−1)≡0modp((k-1)*x_0+b)*(1+k+k^2+k^3+...k^{n-1})\equiv 0\mod p
根据同余的性质,(a∗g)mod(b∗g)(a*g)\mod (b*g)等价于amodba\mod b,于是可以消去gcd(p,(k−1)∗x0+b)gcd(p,(k-1)*x_0+b),剩下的就是求最小的n使得

1+k+k2+k3+...kn−1≡0modq
1+k+k^2+k^3+...k^{n-1}\equiv 0\mod q
两边同乘k−1k-1,由于k−1k-1不一定与q互质,因此由此推出来的式子只是原式的必要条件,我们得到

kn≡1modqk^n\equiv 1\mod q
假如k,q不互质,上式恒不成立,原式无解,否则根据欧拉定理,有

kΦ(q)≡1modqk^{\Phi(q)}\equiv 1\mod q
我们只需要检查Phi(q)的约数,得到最小的n满足条件。Phi(q)的约数,得到最小的n满足条件。

假设真实的答案为ans,根据前面的推导,ans必然为n的倍数,设ans=g∗nans=g*n则

1+k+k2+k3+...kans−1≡g∗(1+k+k2+k3+...kn−1)modq1+k+k^2+k^3+...k^{ans-1}\equiv g*(1+k+k^2+k^3+...k^{n-1})\mod q
因此只需要把n带回去,然后求lcm即可,注意带回去算答案可以只用一个log的复杂度,总复杂度就是分解约数的复杂度*powmod的复杂度,大概是log2plog^2p

#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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: