zoukankan      html  css  js  c++  java
  • bzoj2186

    欧拉函数+逆元

    并没有什么想法

    gcd有一个性质,gcd(i,j)=gcd(i+j,j),这个性质有什么用呢?我们发现phi(m!)找出了在m!以内所有和m互质的数,但是我们没有找到在n!范围内的数,但是根据刚才的性质,gcd(i,j)=gcd(i+j,j),那么gcd(i,m!)=1,gcd(i+m!,m!)=1,所以每个m!以内和m!互质的数都可以通过这个方法拓展,那么对于每个i,算上自己一共可以拓展n!/m!次,那么答案就是phi(m!)*n!/m!

    根据欧拉函数的求法,phi(m!)=m!*π(pi-1)/pi,pi是m!的所有质因子,其实就是m以内所有质数,那么答案就是phi(m!)*n!/m!=π(pi-1)/pi*n!,这肯定是一个整数,然后就线性筛出pi,阶乘和逆元预处理出来就可以O(1)查询了。

    线性求逆元貌似炸了,谁能帮忙看一下

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<vector>
    using namespace std;
    typedef long long ll;
    const int N = 10000010;
    int T;
    ll n, m, p;
    ll ans[N], fac[N], inv[N];
    int pri[500050];
    bool mark[N];
    void ini()
    {
        ans[0] = ans[1] = fac[0] = fac[1] = 1;
        for(int i = 2; i <= 10000000; ++i)
        {
            fac[i] = fac[i - 1] * (ll)i % p;
            if(!mark[i]) pri[++pri[0]] = i;
            ans[i] = 1;
            for(int j = 1; j <= pri[0] && i * pri[j] <= 10000000; ++j)
            {
                mark[i * pri[j]] = 1;
                if(i % pri[j] == 0) break;
            }
        }    
        inv[0] = inv[1] = 1;
        for(int i = 2; i <= 10000000 && i < p; ++i) inv[i] = (ll)(p - p / i * inv[p % i]) % p;
        for(int i = 2; i <= 10000000; ++i) 
        {
            if(!mark[i]) ans[i] = ans[i - 1] * (ll)(i - 1) % p * inv[i % p] % p;
            else ans[i] = ans[i - 1];
        }
    }
    int main()
    {
        cin >> T >> p;
        ini();
        for(; T; --T)
        {
            scanf("%lld%lld", &n, &m);
            printf("%lld
    ", ans[m] % p * fac[n] % p);
        }
        return 0;
    }
    View Code

    exgcd求逆元

    exgcd求逆元,我们求a关于p的逆元x,那么就是a*x=1(mod p),这不就是一个同余方程吗?那么可以转化为ax+py=1,求x的整数解,因为有逆元当且仅当gcd(a,p)==1,所以这个可以直接exgcd,求出x的最小正整数解,最小正整数解是(x%t+t)%t,t=p/gcd(a,p),因为gcd(a,p)==1,所以就是p了

    具体可以看这里

    http://www.cnblogs.com/19992147orz/p/7337301.html

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<vector>
    using namespace std;
    typedef long long ll;
    const int N = 10000010;
    int T;
    ll n, m, p;
    ll ans[N], fac[N];
    int mark[N], pri[N];
    void exgcd(ll a, ll b, ll &x, ll &y)
    {
        if(b == 0)
        {
            x = 1;
            y = 0;
            return;
        }   
        exgcd(b, a % b, y, x);
        y -= (a / b) * x;
    }
    ll inv(ll n)
    {
        ll x, y;
    //  printf("n = %lld p = %lld
    ", n, p);    
        exgcd(n, p, x, y);
        return (x % p + p) % p;
    }
    void ini()
    {
        ans[0] = ans[1] = fac[0] = fac[1] = 1;
        for(int i = 2; i <= 10000000; ++i)
        {
            fac[i] = fac[i - 1] * (ll)i % p;
            if(!mark[i]) pri[++pri[0]] = i;
            ans[i] = 1;
            for(int j = 1; j <= pri[0] && i * pri[j] <= 10000000; ++j)
            {
                mark[i * pri[j]] = 1;
                if(i % pri[j] == 0) break;
            }
        }
        for(int i = 2; i <= 10000000; ++i) 
        {
            if(!mark[i]) ans[i] = ans[i - 1] * (ll)(i - 1) % p * inv(i) % p;
            else ans[i] = ans[i - 1];
        }
    }
    int main()
    {
        cin >> T >> p;
        ini();
        for(; T; --T)
        {
            scanf("%lld%lld", &n, &m);
            printf("%lld
    ", ans[m] % p * fac[n] % p);
        }
        return 0;
    }
    View Code

     发现了一些奇怪的问题,hzwer和popoqqq的程序样例都过不去。。。但是在bzoj上能过。。。线性求逆元是不是有bug啊。。。

  • 相关阅读:
    浅析什么是HOOK
    用diff命令生成Patch,用Patch命令打Patch
    Git 协作:Fetch Pull Push Branch Remote Rebase Cherry-pick相关
    apt-get update 101错误解决办法
    Python函数参数中的冒号与箭头
    Python中的多线程编程,线程安全与锁(二)
    使用pdb模块调试Python
    Python中的多线程编程,线程安全与锁(一)
    聊聊Python中的GIL
    Python中的单元测试模块Unittest快速入门
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7519264.html
Copyright © 2011-2022 走看看