zoukankan      html  css  js  c++  java
  • 「数论全家桶」Strange Way to Express Integers + 古代猪文 + 礼物

    三道题都是比较裸的题,主要是记录一下板子。

    Strange Way to Express Integers

    非常裸的EXCRT,注意一些小细节。

    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    using namespace std;
    const int maxn = 1e5 + 5;
    typedef long long ll;
    ll a[maxn], m[maxn];
    ll x, i, j, d, M;
    ll gcd(ll a, ll b) {
        if (b == 0) return a;
        if (b == 1) return 1;
        return gcd(b, a % b);
    }
    ll lcm(ll a, ll b) {
        return a * b / gcd(a, b);
    }
    ll exgcd(ll a, ll b, ll &x, ll &y) {
        if (b == 0) { x = 1; y = 0; return a; }
        ll d = exgcd(b, a % b, x, y);
        ll k = x;
        x = y, y = k - y * (a / b);
        return d;
    }
    int main() {
        int n;
        while (~scanf("%d", &n)) {
    	for (int s = 1; s <= n; s++) scanf("%lld %lld", &m[s], &a[s]);
    	M = m[1];
    	x = a[1];
    	ll d;
    	int flag = 1;
    	for (int s = 2; s <= n; s++) {
    	    d = exgcd(M, m[s], i, j);
    	    if ((a[s] - x) % d) {
    		printf("-1
    ");
    		flag = 0;
    		break;
    	    }
    	    i = i * ((a[s] - x) / d);
                //将i调整到合适的范围
    	    i = (i % m[s] + m[s]) % m[s];
                //这里不要对x取模,否则会挂的很惨
    	    x = x + i * M;
    	    M = lcm(M, m[s]);
    	}
    	if (flag) printf("%lld
    ", x % M);
        }
        return 0;
    }
    

    古代猪文

    欧拉定理内容

    如果 (gcd(a,p) = 1),那么 (a^{varphi(p)} equiv 1 pmod{p})

    扩展

    在模(p)意义下

    1. (a^b equiv a^{b mod varphi(p)})(gcd(a,p) = 1)
    2. (a^b equiv a^{(b mod varphi(p))+varphi(p)})(gcd(a,p) e 1, varphi(p) leq b)

    然后看这道题,题意是求 (g^{sum_{k|n}{n choose k}} mod 999911659)

    直接做显然会指数爆炸,然后考虑用扩展欧拉定理对指数取模,发现999911659是素数,于是原式变为 (g^{sum_{k|n}{n choose k} mod 999911658} mod 999911659)

    问题转化为求 (sum_{k|n}{n choose k} mod 999911658),发现999911658刚好能拆成4个素数因子相乘,可以用lucas+crt解决,否则就要像下面的礼物一样用exlucas了。

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e5 + 5;
    ll a[5];
    ll jc[maxn];
    ll Qpow(ll x, ll t, ll p) {
        x %= p;
        ll s = 1;
        while (t) {
    	if (t & 1) s = s * x % p;
    	x = x * x % p;
    	t >>= 1;
        }
        return s;
    }
    ll C(ll n, ll m, ll p) {
        if (n < m) return 0;
        if (m == 0) return 1;
        return jc[n] * Qpow(jc[m], p - 2, p) % p * Qpow(jc[n - m], p - 2, p) % p;
    }
    ll Lucas(ll n, ll m, ll p) {
        if (m == 0) return 1;
        return C(n % p, m % p, p) * Lucas(n / p, m / p, p) % p;
    }
    ll n, g;
    ll factor[maxn], p[5] = { 0, 2, 3, 4679, 35617 };
    ll Crt() {
        ll M = 1;
        for (int i = 1; i <= 4; i++) M *= p[i];
        ll ans = 0;
        for (int i = 1; i <= 4; i++)
    	ans = (ans + a[i] * (M / p[i]) % M * Qpow(M / p[i], p[i] - 2, p[i]) % M) % M;
        return ans;
    }
    int main() {
        scanf("%lld %lld", &n, &g);
        if (g % 999911659 == 0) return printf("0
    "), 0;
        for (int i = 1; i * i <= n; i++) {
    	if (n % i == 0) {
    	    factor[++factor[0]] = i;
    	    if (n / i != i) factor[++factor[0]] = n / i;
    	}
        }
        for (int i = 1; i <= 4; i++) {
    	jc[0] = 1;
    	for (int j = 1; j <= p[i]; j++) jc[j] = jc[j - 1] * j % p[i];
    	for (int j = 1; j <= factor[0]; j++)
    	    a[i] = (a[i] + Lucas(n, factor[j], p[i])) % p[i];
        }
        ll x = Crt();
        printf("%lld
    ", Qpow(g, x, 999911659));
        return 0;
    }
    

    礼物

    题意为

    [prod_{i=1}^{n} {{n - sum_{j=1}^{i-1}w[j]} choose w[i]} mod p ]

    问题在于 (p),不一定是质数,而且分解质因子后每个质因子的指数也不一定都是1,所以用exlucas求解每个分问题,注意求逆元因为模数不一定是质数不能用费马小定理,因为每个模数一定互质,最后crt合并即可。

    附exlucas讲解:学exlucas这一篇就够了,吹爆Midoria7%%%

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <iostream>
    #include <cmath>
    using namespace std;
    const int maxn = 20;
    typedef long long ll;
    
    void Ex_gcd(ll a, ll b, ll &x, ll &y) {
        if (!b) { x = 1, y = 0; return; }
        Ex_gcd(b, a % b, x, y);
        ll z = x;
        x = y, y = z - y * (a / b);
    }
    
    ll Inv(ll a, ll b) {
        ll x, y;
        Ex_gcd(a, b, x, y);
        return (x % b + b) % b;
    }
    
    ll Qpow(ll x, ll t, ll mod) {
        ll s = 1;
        while (t) {
    	if (t & 1) s = s * x % mod;
    	x = x * x % mod;
    	t >>= 1;
        }
        return s;
    }
    
    ll Fac(ll n, ll p, ll pk) {
        if (!n) return 1;
        ll res = 1;
        for (ll i = 1; i <= pk; i++) if (i % p) res = res * i % pk;
        res = Qpow(res, n / pk, pk);
        for (ll i = 1; i <= n % pk; i++) if (i % p) res = res * i % pk;
        return res * Fac(n / p, p, pk) % pk;
    }
    
    ll C(ll n, ll m, ll p, ll pk) {
        ll x = 0, y = 0, z = 0;
        for (ll i = p; i <= n; i *= p) x += n / i;
        for (ll i = p; i <= m; i *= p) y += m / i;
        for (ll i = p; i <= n - m; i *= p) z += (n - m) / i;
        return (Fac(n, p, pk) * Inv(Fac(m, p, pk), pk) % pk * Inv(Fac(n - m, p, pk), pk) % pk * Qpow(p, x - y - z, pk) % pk) % pk;
    }
    
    ll Crt(ll n, ll a[], ll mod[]) {
        ll M = 1, res = 0;
        for (int i = 1; i <= n; i++) M *= mod[i];
        ll w, x, y;
        for (int i = 1; i <= n; i++) {
    	w = M / mod[i];
    	res = (res + a[i] * Inv(w, mod[i]) * w % M) % M;
        }
        return res;
    }
    
    ll Ex_lucas(ll n, ll m, ll P) {
        ll mod[20], a[20], cnt = 0;
        for (ll i = 2; i * i <= P; i++) {
    	if (P % i == 0) {
    	    mod[++cnt] = 1;
    	    while (P % i == 0) {
    		mod[cnt] *= i;
    		P /= i;
    	    }
    	    a[cnt] = C(n, m, i, mod[cnt]);
    	}
        }
        if (P > 1) mod[++cnt] = P, a[cnt] = C(n, m, P, P);
        return Crt(cnt, a, mod);
    }
    
    #define cnt pk[0]
    ll ans[maxn], pk[maxn];
    
    int main() {
        ll n, m, p, w[10];
        scanf("%lld %lld %lld", &p, &n, &m);
        for (int i = 1; i <= m; i++) scanf("%lld", &w[i]);
        for (ll i = 2; i * i <= p; i++) {
    	if (p % i == 0) {
    	    pk[++cnt] = 1;
    	    while (p % i == 0) {
    		pk[cnt] *= i;
    		p /= i;
    	    }
    	}
        }
        if (p > 1) pk[++cnt] = p;
        for (int i = 1; i <= cnt; i++) ans[i] = 1;
        ll sum = 0;
        for (int i = 1; i <= m; i++) sum += w[i];
        if (sum > n) return printf("Impossible
    "), 0;
        sum = 0;
        for (int i = 1; i <= m; i++) {
    	for (int j = 1; j <= cnt; j++) {
    	    ans[j] = (ans[j] * Ex_lucas(n - sum, w[i], pk[j]) % pk[j]) % pk[j];
    	}
    	sum += w[i];
        }
        printf("%lld
    ", Crt(cnt, ans, pk));
        return 0;
    }
    
  • 相关阅读:
    一文带你看清HTTP所有概念
    程序员不得不了解的硬核知识大全
    看完这篇HTTP,跟面试官扯皮就没问题了
    ReentrantLock 源码分析从入门到入土
    计算机网络的核心概念
    Kafka 的这些原理你知道吗
    2019 我是怎么熬过来的?
    不懂什么是锁?看看这篇你就明白了
    机器学习——方差、协方差与皮尔逊值
    最小生成树的本质是什么?Prim算法道破天机
  • 原文地址:https://www.cnblogs.com/Zfio/p/13761565.html
Copyright © 2011-2022 走看看