CodeForces - 919E(费马小定理)

题目链接

题意:给定 abpxnanbmodp a , b , p , x , 求 n ∗ a n ≡ b ( m o d p )
可以设 n=i(p1)+j n = i ∗ ( p − 1 ) + j ,那么原式就等于 (i(p1)+j)ai(p1)+jb(modp) ( i ∗ ( p − 1 ) + j ) ∗ a i ∗ ( p − 1 ) + j ≡ b ( m o d p ) 根据费马小定理 ap11(modp) a p − 1 ≡ 1 ( m o d p ) ,就可以化简为 ji=b/aj,i=jb/aj j − i = b / a j , 也 就 是 i = j − b / a j (这里的除法可以用乘法逆元来求),那么我们就可以通过枚举 j j 来确定i的值,也就可以确定 n n 的值了。
然后来讨论循环节的问题,对于任意一个数x,在 x<p x < p 的时候,x取任何值,进行 x%p x % p 操作之后的值都是不同的,然而当 x>=p x >= p 之后就会和 x<p x < p 的取模之后的值重复,这里就把 p p 叫作x的循环节。
那么 n%p n % p 的循环节就是p了,那么根据费马小定理,我们也可以得出a^n\%p的循环节是(p-1),那么对于原式左边得循环节就是p*(p-1),也就是说,在 p(p1) p ∗ ( p − 1 ) 的范围内,原式左边只会出现一个可行解。那可以令 P=p(p1) P = p ∗ ( p − 1 ) ,然后直接用所给的边界 x/P x / P ,然后在考虑x%P的部分与所求出n的关系就可以了。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
long long mod,ans;
long long quickpow(long long a,long long b)
{
    if(b<0)return 0;
    long long ret=1;
    a%=mod;
    while(b)
    {
        if(b&1)
            ret=(ret*a)%mod;
        b>>=1;
        a=(a*a)%mod;
    }
    return ret;
}
long long inv(long long a)
{
    return quickpow(a,mod-2);
}
int main()
{
    long long a,b,p,x;
    while(~scanf("%lld %lld %lld %lld",&a,&b,&p,&x))
    {
        mod = p;
        ans = 0;
        long long P = p * (p - 1);
        for (long long j = 0; j < p - 1; j++)
        {
            long long temp = b * inv(quickpow(a,j)) % p;
            long long i = (j - temp + p) % p;
            long long n = (i * (p - 1) + j)%P;
            if(n == 0)n = P;
            ans += x/P;
            if(x % P >= n)
            {
                ans++;
            }
        }

        printf("%lld\n",ans);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值