• 【学术篇】SDOI2008 沙拉公主的困惑


    传送门!

    题目在里...

    题目大意?

    难道不是说的很清楚了么OvO
    求n!中与m!互质的数的个数..

    题目分析.

    显然的数论... 所以就是化式子呗..
    一个很显然的性质就是如果(gcd(a,b)=1),那么(gcd(a+kb,b)=1)...
    而题目中说了(mleqslant n), ∴ (m!|n!)
    于是我们只需要计算(m!)中与(m!)互质的数的个数,然后乘以(frac{n!}{m!})即可..
    我们发现上面加粗的这一坨就是(varphi(m!))嘛...
    所以(ans=varphi(m!)*frac{n!}{m!})
    又有(varphi(x)=x*prod_{i}^{n}(1-frac{1}{p_i})) 其中(p_i)表示x的质因数...
    (m!=1*2*...*m), 所以(m!)的质因数很显然就是不大于(m)的质数...
    然后带入上式约掉(m!)就有了(ans=n!*prod_{i}^{n}frac{p_i-1}{p_i}) (其中(p_ileqslant m)(p_i)为质数)...
    由于多组询问, 而且内存开了256MB不是 所以我们要预处理... 不然会T...
    由于上式, 我们要预处理的东西有:

    • 筛素数(简单欧拉筛)
    • 阶乘(顺着乘一遍取模就行了)
    • 逆元(要递推求出所有数的哦) (所以最好用(O(n))的, 不会的话直接看代码就行了 百度一下一堆详细讲解OvO)
    • (mul_i=prod_{i}^{n}frac{p_i-1}{p_i})这一坨东西...(不大于(m)的质数(p_i)们的((1-frac{1}{p_i}))的乘积...)
      然后处理这一坨的时候也很容易...递推即可.. 显然, 我们有
    1. (i)是质数时, (mul_i=mul_{i-1}*frac{i-1}{i})
    2. 否则(mul_i=mul_{i-1})即可...
      这样就做完了.

    实现代码:

    #include <cstdio>
    typedef long long LL;
    const int X=1e7+3;
    inline int gn(int a=0,char c=0){
        for(;c<48||c>57;c=getchar());
        for(;c>47&&c<58;c=getchar())
            a=a*10+c-48; return a;
    }
    int inv[X],fac[X],eu[X],mul[X],pri[X/10],tot;
    bool notp[X]; int T,R,M,N;
    void prime(){
        notp[1]=1;
        for(int i=2;i<X;++i){
            if(!notp[i])pri[++tot]=i;
            for(int j=1;j<=tot&&i*pri[j]<=1e7;++j){
                notp[i*pri[j]]=1; if(i%pri[j]==0) break;
            }
        }
    }
    void calcinv(){
        inv[1]=1;
        for(int i=2;i<X;++i){
            inv[i]=(LL)(R-R/i)*inv[R%i]%R;
            if(inv[i]<0) inv[i]+=R;
        }
    }
    void calcfac(){
        fac[1]=1;
        for(int i=2;i<X;++i)
            fac[i]=(LL)fac[i-1]*i%R;
    }
    void calcmul(){
        mul[1]=1;
        for(int i=2;i<X;++i)
            if(!notp[i]) mul[i]=(LL)mul[i-1]*(i-1)%R*inv[i]%R;
            else mul[i]=mul[i-1];
    }
    int main(){
        T=gn(),R=gn();
        prime(); calcinv(); calcfac(); calcmul();
        while(T--){
            N=gn(),M=gn();
            printf("%d
    ",(int)((LL)fac[N]*mul[M]%R));
        }
    }
    

    注意事项~

    1. 做乘法的时候要转long long,(当然你要是全用long long算当我没说
    2. 预处理的时候1的值作为边界值给出, 循环要从2开始
    3. 每一步都记得取模
    4. 输出的时候记得换行而不是空格(我是不是暴露了什么←_←

    完结撒花

  • 相关阅读:
    cpp 模版函数
    叉积
    利用scrollTop 制作图片无缝滚动
    事件绑定和时间取消
    闭包写法
    增加类,删除类,查找类
    获取元素到页面上的位置
    在IE8中如何通过javascripts改变<style />中的内容?
    有关app的一些小知识
    获取页面高宽知识
  • 原文地址:https://www.cnblogs.com/enzymii/p/8412195.html
Copyright © 2020-2023  润新知