zoukankan      html  css  js  c++  java
  • 清北学堂 清北-Day1-R1-Count

    题目描述
    问有几个无序二元组 (x; y) 满足 xy ≡ 1 (mod P ); 0 ≤ x < P; 0 ≤ y <P。无序二元组是指,如果 P = 10, (3; 7) 和 (7; 3) 只算一次。

    输入
    一行一个正整数 P。

    输出
    一行一个数,表示答案。

    样例输入

    10
    

    样例输出

    3
    

    【样例输入 2】

    8000000
    

    【样例输出 2】

    1600004
    

    【数据范围与子任务】
    Subtask1(20pts) $ P le 10^3 $
    Subtask2(30pts) $ P le 10^5 $
    Subtask3(50pts) $ P le 10^7 $

    本来以为是一道神仙数论题,结果是一道SB数论题
    首先观察题目给出的式子: $ x imes y equiv 1 pmod p $
    是不是感觉有一点似曾相识?
    如果没有,那说明你逆元学得不太好(或者说没理解)
    我们可以发现,这个式子正是在模 $ p $ 意义下 $ x $ 的逆元定义式
    但是我们发现,这里的 $ p $ 不一定是一个质数,所以不能直接用逆元的方式来算
    但是,我们知道逆元存在的条件的 $ x $ 与模数 $ p $ 互质,所以我们可以通过欧拉函数值 $ phi (n) $ 来求出部分答案
    欧拉函数: $ phi (n) $ 表示小于等于 $ n $ 的数字中有多少个数字与 $ n $ 互质
    欧拉函数可以通过线性筛筛出,代码如下:

    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    
    const int maxn=1e7+5;
    
    int prime[maxn],phi[maxn];
    int cnt=0,n,m;
    bool vis[maxn];
    
    void get_phi(int n){
        phi[1]=1;vis[1]=1;
        for(int i=2;i<n;++i){
            if(!vis[i]){                           
                prime[++cnt]=i;
                phi[i]=i-1;
            }
            for(int j=1;j<=cnt&&i*prime[j]<=n;++j){
                vis[i*prime[j]]=true;
                if(!(i%prime[j])){
                    phi[i*prime[j]]=phi[i]*prime[j];
                    break;
                }
                else phi[i*prime[j]]=phi[i]*(prime[j]-1);
            }
        }
    }
    
    int main(){
    	scanf("%d%d",&n,&m);
    	get_phi(n+5);
    	while(m--){
    		register int x;
    		scanf("%d",&x);
    		puts(vis[x]?"No":"Yes");
    	}
    	return 0;
    }
    

    也可以使用单个欧拉函数值的求法,复杂度是 $ Theta sqrt{n} $
    在这个题目中显然后一种比较优秀,这里也同样给出代码:

    inline int Euler(int n){
        register int res=n,a=n;
        for(int i=2;i*i<=a;i++){
            if(a%i==0){
            	res=res/i*(i-1);
                while(a%i==0) a/=i;
            }
        }
        if(a>1) res=res/a*(a-1);
        return res;
    }
    

    千万不要以为这时候这道题就做完了,其实我们还需要考虑一种情况:
    当 $ x = y $ 的时候,也即是 $ x^2 equiv 1 pmod p $
    这种情况也是满足的,所以也要把这种情况统计上,这样这道题才算是AC了
    AC代码:

    #include <algorithm>
    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #define ll long long
    
    int mod,ans;
    
    inline int Euler(int n){
        register int res=n,a=n;
        for(int i=2;i*i<=a;i++){
            if(a%i==0){
            	res=res/i*(i-1);
                while(a%i==0) a/=i;  
            }
        }
        if(a>1) res=res/a*(a-1);
        return res;
    }
    
    int main(){
    	scanf("%d",&mod);
    	ans+=Euler(mod);
    	for(ll i=1;i<=mod;++i) if(i*i%mod==1) ++ans;
    	printf("%d
    ",(ans>>1));
    	return 0;
    }
    
    May you return with a young heart after years of fighting.
  • 相关阅读:
    使用bootstrap中的toolTip插件时 最上方提示会被遮挡问题
    Vue中splice的使用
    由于eslint语法检查工具限制很严格,导致启动项目是报错的解决办吧(使用cmder工具时发生的错误)
    windows命令行工具—Cmder配置
    mui触发自定义事件(子页面返回传递给父级页面值)
    计算最长英语单词链
    周总结14
    找水王
    用户体验评价
    周总结13
  • 原文地址:https://www.cnblogs.com/Equinox-Flower/p/9892287.html
Copyright © 2011-2022 走看看