hdu5393 Falsyta in Tina Town

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5393
题意:给出 k,b,x0,p , xn=(xn1k+b)modp ,求最小的n,使得 xn=x0 ,如果不存在输出-1。
分析:通过简单的数学推导,题目即求最小的n使得

((k1)x0+b)(1+k+k2+k3+...kn1)0modp
根据同余的性质, (ag)mod(bg) 等价于 amodb ,于是可以消去 gcd(p,(k1)x0+b) ,剩下的就是求最小的n使得
1+k+k2+k3+...kn10modq
两边同乘 k1 ,由于 k1 不一定与q互质,因此由此推出来的式子只是原式的必要条件,我们得到
kn1modq
假如k,q不互质,上式恒不成立,原式无解,否则根据欧拉定理,有
kΦ(q)1modq
我们只需要检查 Phi(q)n
假设真实的答案为ans,根据前面的推导,ans必然为n的倍数,设 ans=gn
1+k+k2+k3+...kans1g(1+k+k2+k3+...kn1)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);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值