zoukankan      html  css  js  c++  java
  • Codeforces 919E Congruence Equation ( 数论 && 费马小定理 )

    题意 : 给出数 x (1 ≤ x ≤ 10^12 ),要求求出所有满足 1 ≤ n ≤ x 的 n 有多少个是满足 n*a^n  = b ( mod p )

    分析 :

    首先 x 的范围太大了,所以使用枚举进行答案的查找是行不通的

    观察给出的同余恒等式,发现这个次方数 n 毫无规律

    自然想到化成费马小定理的形式

    令 n = i*(p-1)+j 

    式子化成 

    根据费马小定理不难证明(猜???)周期为 p*(p-1)

    ==> 来自 Tutorial,反正我是不知道怎么证,貌似评论下面有大神用欧拉函数来证

    有一个点要提前说一下,我们观察等式中间部分的指数部分

    发现如果 j == 0 的话那么在模 p-1 意义下 n 就会变成 0

    但是题目给出的范围 n 是不允许为 0 的,所以等等解法里面会把 j == 0 用 j == p-1 代替

    然后将刚刚得出的化简结果代回题目原式,于是就可以枚举 j (范围是 1~p-1)来得到 i

    此时的得出来的 i 和 j 都是刚刚好满足原式的,于是可得满足原式的最小 n

    因为周期是 p*(p-1) 所以后面更大的满足题意的 n 应该为 n+k*[p*(p-1)],而这里我们不加上周期,故得最小

    又因为得知周期为 p*(p-1)所以答案的贡献应该为 ( x - n ) / [p*(p-1)] ==> x > n

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    
    LL pow_mod(LL a, LL b, LL p)
    {
        LL ret = 1;
        while(b){
            if(b & 1) ret = (ret * a) % p;
            a = (a * a) % p;
            b >>= 1;
        }
        return ret;
    }
    
    LL Fermat(LL a, LL p)
    { return pow_mod(a, p-2, p); }
    
    int main(void)
    {
        LL a, b, x, p;
        while(~scanf("%I64d %I64d %I64d %I64d", &a, &b, &p, &x)){
            LL ans = 0;
            for(LL j=1; j<=p-1; j++){
                LL y = b * Fermat(pow_mod(a, j, p), p) % p;
                LL Min_N = (p-1) * ((j - y + p)%p) + j;
                if(Min_N > x) continue;
                ans += (x - Min_N) / (p*(p-1)) + 1LL;
            }
            printf("%I64d
    ", ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    脚本执行策略设置
    获取日期与时间戳小笔记
    Intellij IDEA部分简介
    Intellij IDEA脚本参数化、关联、检查点
    LR中的时间戳
    LeetCode 35.Search Insert Position
    LeetCode 34.Search for a Range
    LeetCode 33.Search in Rotated Sorted Array(M)
    LeetCode 81.Search in Rotated Sorted Array II(M)
    LeetCode 278.First Bad Version(E)(P)
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/8431045.html
Copyright © 2011-2022 走看看