zoukankan      html  css  js  c++  java
  • BUPT2017 springtraining(16) #4 ——基础数论

    题目在这里

    A.手动打表找规律得组合数

    n -= 2, m -= 2, ans = C(n, m)

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    
    const int Mod = 1e9 + 7;
    
    ll fac[200010];
    
    ll calc(ll x, int k = Mod - 2) {
        ll ret = 1;
        for(;k;k >>= 1, x = x * x % Mod)
            if(k & 1) ret = ret * x % Mod;
        return ret;
    }
    
    int main() {
        ios::sync_with_stdio(false);
        int n, m;
        fac[0] = fac[1] = 1;
        for(int i = 2;i <= 200000;i ++) 
            fac[i] = fac[i - 1] * i % Mod;
        while(cin >> n >> m) {
            if(n > m) swap(n, m);
            cout << fac[m + n - 4] * calc(fac[n - 2]) % Mod * calc(fac[m - 2]) % Mod << endl;
        }
        return 0;
    }
    View Code

    B.

    C.裸快速幂

    #include <cstdio>
    
    using namespace std;
    
    double x = 1.000000011;
    
    double n;
    
    long long k;
    
    int main() {
        scanf("%lf %lld", &n, &k);
        for(;k;k >>= 1, x = x * x)
            if(k & 1) n = n * x;
        printf("%.8f
    ", n);
        return 0;
    }
    View Code

    D.递推式那么明显当然是矩阵快速幂啦

    唯一需要注意的是,自乘矩阵的填充方式...

    开始时,a1 对应 f(d) , a2 对应 f(d - 1) ...

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    
    int d, n, m;
    
    struct  matrix1{
        ll c[15][15];
        matrix1() {
            memset(c, 0, sizeof c);
        }
        void init() {
            memset(c, 0, sizeof c);
            for(int i = 0;i < d;i ++) cin >> c[d - 1 - i][d - 1], c[d - 1 - i][d - 1] %= m;
            for(int i = 1;i < d;i ++) c[i][i - 1] = 1;
        }
        matrix1 operator *(const matrix1 &a) const {
            matrix1 ret;
            for(int k = 0;k < d;k ++)
                for(int i = 0;i < d;i ++)
                    if(c[i][k])
                        for(int j = 0;j < d;j ++)
                            ret.c[i][j] = (ret.c[i][j] + c[i][k] * a.c[k][j]) % m;
            return ret;
        }
    };
    
    struct  matrix2{
        ll c[15];
        matrix2() {
            memset(c, 0, sizeof c);
        }
        void init() {
            memset(c, 0, sizeof c);
            for(int i = 0;i < d;i ++) cin >> c[i], c[i] %= m;
        }
        matrix2 operator *(const matrix1 &a) const {
            matrix2 ret;
            for(int i = 0;i < d;i ++)
                for(int j = 0;j < d;j ++)
                    ret.c[i] = (ret.c[i] + c[j] * a.c[j][i]) % m;
            return ret;
        }
    };
    
    int main() {
        matrix1 c1;
        matrix2 c2;
        while(cin >> d >> n >> m, d != 0) {
            c1.init(), c2.init();
            for(n --;n;n >>= 1, c1 = c1 * c1)
                if(n & 1) c2 = c2 * c1;
            cout << c2.c[0] << endl;
        } 
        return 0;
    }
    View Code

    E.参考 CodeForces - 785D 

    F.看样例猜结论就好了

    输出所有质数的幂就好了

    #include <iostream>
    
    using std::cin;
    using std::endl;
    using std::cout;
    
    int n, v[1011], p[1011];
    
    int main() {
        cin >> n;
        for(int i = 2;i <= n;i ++) {
            if(!v[i]) {
                for(int j = i;j <= n;j *= i)
                    p[++ p[0]] = j;
            }
            for(int j = i << 1;j <= n;j += i)
                v[j] = 1;
        }
        cout << p[0] << endl;
        for(int i = 1;i <= p[0];i ++)
            cout << p[i] << " ";
        return 0;
    }
    View Code

    G.参考 CodeForces - 785C

    H.

    I.能被 6 整除一定能被 2 和 3 整除,8 和 9 同理

    于是就是求 1 - n 内2 3 5 7的倍数之和

    容斥原理即可

    #include <iostream>
    
    using namespace std;
    
    int main() {
        long long n;
        cin >> n;
        cout << n - n / 2 - n / 3 - n / 5 - n / 7 + n / 6 + n / 10 + n / 14 + n / 35 + n / 21 + n / 15 - n / 105 - n / 70 - n / 42 - n / 30 + n / 210;
        return 0;
    }
    View Code

    J.

    K.对于n 的每一个因数 t 

    它对答案贡献为 t * phi(n / t)

    效率玄学吧

    #include <cstdio>
    
    int v[60000], p[60000];
    
    int phi(int x) {
        int ret = x;
        for(int i = 1;1ll * p[i] * p[i] <= x;i ++)
            if(x % p[i] == 0) {
                ret = ret - ret / p[i];
                while(x % p[i] == 0) x /= p[i];
            }
        if(x != 1) ret -= ret / x;
        return ret;
    }
    
    int main() {
        long long n, ans;
        for(int i = 2;i < 60000;i ++) {
            if(!v[i]) p[++ p[0]] = i;
            for(int j = 1;j <= p[0] && p[j] * i < 60000;j ++) {
                v[p[j] * i] = 1;
                if(i % p[j] == 0) break;
            }
        }
        while(scanf("%lld", &n) != EOF) {
            ans = 0;
            for(long long i = 1;i * i <= n;i ++) {
                if(n % i)  continue;
                ans += i * phi(n / i);
                if(i * i != n) ans += n / i * phi(i);
            }
            printf("%lld
    ", ans);
        }
        return 0;
    }
    View Code

    L.和式加一项减一项变成了C(n + m, n)

    n,m 大 p 小且 p 保证为质数,使用卢卡斯定理

    Lucas(n,m) % p = Lucas(n / p,m / p) * Comb(n % p,m % p) % p

    注意lucas里面的取模后计算组合数,可能会出现 C(n,m) 里 n < m

    所以Comb函数里需要判断的

    考虑 p 为读入的不能预处理,所以我们有两种解决方案

    1.每组数据 O(p) 预处理处阶乘 fac 

    Comb就可以 O(logn) 回答,理论效率 O(p + logn * log(p)(n + m))

    大概就是 O(p)

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    
    int t, n, m, p;
    
    ll fac[100010];
    
    ll calc(ll x, int k = p - 2) {
        ll ret = 1;
        for(;k;k >>= 1, x = x * x % p)
            if(k & 1) ret = ret * x % p;
        return ret;
    } 
    
    ll C(int n, int m) {
        if(n < m) return 0;
        return fac[n] * calc(fac[m]) % p * calc(fac[n - m]) % p;
    }
    
    ll lucas(int n, int m) {
        if(!m) return 1;
        return C(n % p, m % p) * lucas(n / p, m / p) % p;
    }
    
    int main() {
        ios::sync_with_stdio(false);
        fac[0] = 1;
        cin >> t;
        while(t --) {
            cin >> n >> m >> p;
            for(int i = 1;i < p;i ++) fac[i] = fac[i - 1] * i % p;
            cout << lucas(n + m, n) << endl;
        }
        return 0;
    }
    View Code

    2.不进行预处理,Comb直接 O(p + logn) 回答 

    理论效率O(p * log(p)(n + m))

    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    
    int t, n, m, p;
    
    ll calc(ll x, int k = p - 2) {
        ll ret = 1;
        for(;k;k >>= 1, x = x * x % p)
            if(k & 1) ret = ret * x % p;
        return ret;
    } 
    
    ll C(int n, int m) {
        if(n < m) return 0;
        ll ret1 = 1, ret2 = 1;
        for(int i = 1, j = n;i <= m;i ++, j --) {
            ret1 = ret1 * i % p;
            ret2 = ret2 * j % p;
        }
        return ret2 * calc(ret1) % p;
    }
    
    ll lucas(int n, int m) {
        if(!m) return 1;
        return C(n % p, m % p) * lucas(n / p, m / p) % p;
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin >> t;
        while(t --) {
            cin >> n >> m >> p;
            cout << lucas(n + m, n) << endl;
        }
        return 0;
    }
    View Code

    然而第二种的表现更好...因为都是最坏时间估计

    而第一种稳定在O(p),第二种实际是几倍优于最坏效率的

    M.

  • 相关阅读:
    GIT学习实践笔记
    ubuntu 安装pygit2
    强化vim打造python的IDE
    Python Django学习和实践
    浏览器调试工具网页性能分析中的使用
    公司发版shell脚本重构
    Nightwatch+gulp
    Git
    JavaScript Unit Test with Qunit
    Unit Test Mocking Framework
  • 原文地址:https://www.cnblogs.com/ytytzzz/p/6929504.html
Copyright © 2011-2022 走看看