• 洛谷 P2155 [SDOI2008]沙拉公主的困惑


    传送门:https://www.luogu.com.cn/problem/P2155


    题目大意

    • (1 , 2 , …… , n !) 中,与 (m !) 互质的数的个数

    Solution

    • 对于上述问题,我们可以转换为求:在 (1 , …… , n !) 中,不含小于 (m) 的质数为因子的数的个数

      (即:设 (p_1 , p_2 , …… , p_k) 为不大于 (M) 的质数,求在 (1 , …… , n!) 中,不包含因子 (p_1 , p_2 , …… , p_k) 的数的个数)

    • 则我们可以将 (1)(n!) 分为若干段长度为 (m!) 的数列,其中的每一段中与 (m!) 互质的数的个数等于 (1)(m!) 中与 (m!) 互质的数的个数

      那么,我们可以获得如下式子:(ans = frac{n!}{m!} imes varphi{(m!)}) ,而 (varphi{(m!)} = m! imes frac{prod{(p_i-1)}}{prod{p_i}})

      则上述公式可以转换为:(ans = n! imes frac{prod{(p_i-1)}}{prod{p_i}})

    • 则我们可以在线性时间内将 (n!)(prod{p_i-1})(prod{p_i})预处理得到,在每次询问时直接 (O(1)) 查询 (n!)(prod{p_i-1}) ,再用费马小定理结合快速幂求得 (prod{p_i}) 的逆元,相乘即可

    Code

    #include<iostream>
    #include<algorithm>
    #include<math.h>
    #include<cstring>
    #include<cstdio>
    #define ll long long
    using namespace std;
    
    const ll maxn=10000010;
    ll t,r,n,m,tot;
    ll jie[maxn],f1[maxn],f2[maxn],prime[maxn];
    bool vis[maxn];
    
    void Init(ll x){ \线性筛
    	memset(vis,true,sizeof(vis));
    	vis[0] = vis[1] = false;
    	for(int i = 2;i <= x;i++){
    		if(vis[i])
    			prime[++tot] = i;
    		for(int j = 1;j <= tot && i * prime[j] <=x ;j++){
    			vis[i * prime[j]] = false;
    			if(i % prime[j] == 0)
    			    break;
    		}
    	}
    }
    inline ll ksm(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;
    }
    
    int main(void)
    {
        scanf("%lld%lld",&t,&r);
    
        Init(maxn-5);
        jie[1]=f1[1]=f2[1]=1;
    
        for(int i=2;i<=maxn-5;i++) \预处理
        {
            jie[i]=jie[i-1]*i%r;
    
            if(vis[i])
            {
                f1[i]=f1[i-1]*(i-1)%r; 
                f2[i]=f2[i-1]*i%r;
            }
            else
            {
                f1[i]=f1[i-1];
                f2[i]=f2[i-1];
            }
        }
    
        while(t--)
        {
            scanf("%lld%lld",&n,&m);
    
            printf("%lld
    ",(jie[n]*f1[m]%r)*ksm(f2[m],r-2,r)%r);
        }
    
        return 0;
    }
    
  • 相关阅读:
    zookeeper部署
    Hadoop集群的构建和安装
    numpy ndarray求其最值的索引
    两数之和
    盛最多水的容器
    mysql 单表卡死
    Leetcode 258. Add Digits
    Matlab中添加路径与去除路径
    Leetcode 136 Single Number
    Leetcode 485. Max Consecutive Ones
  • 原文地址:https://www.cnblogs.com/jd1412/p/13519877.html
Copyright © 2020-2023  润新知