• SCUT


    https://scut.online/p/485

    给定a和n,求有多少个质数p,满足n是使得a^n=1 mod p成立的最小正整数。

    翻译:求有多少个质数p,使得a模p的阶delta_m(a)是n

    先验证 a^n=1 mod p 成立

    那么假如还有更小的m使得 a^m=1 mod p 成立,则这个p不合要求

    由阶的性质有delta_m(a)|n,故只需要检查n的所有因子就可以了。

    但其实不需要检查所有因子,只需要检查n的所有质因子。(从板子上面可以看出来,但是为什么)

    即 a^(p_i) = 1 mod p 是否成立,假如恒不成立,则n是a模p的阶,其中p_i是n的每种质因子。

    证明如下:很显然的,原本我们要检查n的所有因子才能确定阶,但是有一个更好的办法。

    假如还有更小的m使得 a^m=1 mod p 成立,那么m的倍数km也一定满足 a^(km)=1 mod p 成立,那么从n中只去除一个质因子p_i,假如这个t=(n/p_i)有 a^t=1 mod p ,则可能存在更小的m使得 a^m=1 mod p 成立。否则假如 a^t != 1 mod p ,则t的所有因子也都不需要检查了。

    这样就只需要检查log次。

    1e9都直接暴力,快速幂还有个logn,真的服了没话讲。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    int q, n;
    
    const int MAXN = 1e7 + 5;
    
    int p[MAXN], ptop;
    int minp[MAXN];
    bool np[MAXN];
    
    void sieve(int n) {
        np[1] = 1;
        for(int i = 2; i <= n; i++) {
            if(!np[i]) {
                p[++ptop] = i;
                minp[i] = i;
            }
            for(int j = 1, t; j <= ptop && (t = i * p[j]) <= n; j++) {
                minp[t] = p[j];
                np[t] = 1;
                if(i % p[j] == 0)
                    break;
            }
        }
    }
    
    int qpow(ll x, int n, int p) {
        ll res = 1;
        while(n) {
            if(n & 1)
                res = res * x % p;
            x = x * x % p;
            n >>= 1;
        }
        return res;
    }
    
    int ans[MAXN], atop;
    
    int fac[60], ftop;
    
    void GetFactor(int n) {
        ftop = 0;
        while(n != 1) {
            int cp = minp[n];
            fac[++ftop] = cp;
            while(n % cp == 0)
                n /= cp;
        }
    }
    
    int check(int n, int P) {
        if(qpow(q, n, P) != 1)
            return 0;
        for(int i = 1; i <= ftop; ++i) {
            int t = n / fac[i];
            if(qpow(q, t, P) == 1)
                return 0;
        }
        return 1;
    }
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
    #endif // Yinku
        sieve(MAXN);
        while(~scanf("%d%d", &q, &n)) {
            GetFactor(n);
            atop = 0;
            for(int i = 1; i <= ptop; ++i) {
                if(check(n, p[i]))
                    ans[++atop] = p[i];
            }
            printf("%d
    ", atop);
            for(int i = 1; i <= atop; ++i)
                printf("%d%c", ans[i], " 
    "[i == atop]);
        }
        return 0;
    }
    

    直接上BSGS的话,假如这样的p有10000个就比较麻烦。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    int q, n;
    
    const int MAXN = 1e7 + 5;
    
    int p[MAXN], ptop;
    bool np[MAXN];
    
    void sieve(int n) {
        np[1] = 1;
        for(int i = 2; i <= n; i++) {
            if(!np[i])
                p[++ptop] = i;
            for(int j = 1, t; j <= ptop && (t = i * p[j]) <= n; j++) {
                np[t] = 1;
                if(i % p[j] == 0)
                    break;
            }
        }
    }
    
    int qpow(ll x, int n, int p) {
        ll res = 1;
        while(n) {
            if(n & 1)
                res = res * x % p;
            x = x * x % p;
            n >>= 1;
        }
        return res;
    }
    
    unordered_map<int,int> M;
    int bsgs(int a,int b,int n,int k=1,int t=0){
        /*if(b==1)
            return 0;*/
        M.clear();
        int m=ceil(sqrt(n));
        ll s=b;
        for(int i=0;i<m;++i,s=s*a%n){
            M[s]=i;
        }
        s=k;
        k=qpow(a,m,n);
        for(ll i=1;i<=m;++i){
            s=s*k%n;
            if(M.count(s))
                return i*m-M[s]+t;
        }
        return -1;
    }
    
    
    int ans[MAXN], atop;
    
    int check(int n, int p) {
        if(qpow(q, n, p) != 1)
            return 0;
        int res=bsgs(q,1,p);
        if(res==-1||res==n)
            return 1;
        return 0;
    }
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
    #endif // Yinku
        sieve(MAXN);
        while(~scanf("%d%d", &q, &n)) {
            atop = 0;
            for(int i = 1; i <= ptop; ++i) {
                if(check(n, p[i]))
                    ans[++atop] = p[i];
            }
            printf("%d
    ", atop);
            for(int i = 1; i <= atop; ++i)
                printf("%d%c", ans[i], " 
    "[i == atop]);
        }
        return 0;
    }
    
  • 相关阅读:
    如何实现一个php框架系列文章【3】支持psr4的自动加载类
    JavaScript中valueOf函数与toString方法的使用
    js中null和undefined
    学习笔记(二)JavaScript基本概念(语法,数据类型,控制语句,函数)
    学习笔记(-)在html中使用javascript
    将用户输入的字符串反向输出到页面上,并且要求将其中的小写字母转换成大写字母。
    设计一个表单,放入两个按钮,单击它们时将显示不同问候语。
    编写一个函数,在页面上输出1~1000之间所有能同时被3,5,7整除的证书,并要求每行显示6个这样的数
    innerHTML、outerHTML、innerText、outerText的用法与
    web笔试题(3)
  • 原文地址:https://www.cnblogs.com/Yinku/p/11337094.html
Copyright © 2020-2023  润新知