• HDU 4407 Sum 容斥原理


    回忆 HDU 4135 经典题 Co-Prime 求[a,b]区间与给定素数p互质的个数。 将p质因数分解后容斥即可。 原理就是质因数的倍数就是与p不互素的数。

    此题的写法:

    ll p[maxn];
    int cnt;
    ll n;
    
    void init(ll m) {
        for (int i = 2; i * i <= m; i++) {
            if (m % i == 0) {
                p[cnt++] = i;
                while (m % i == 0) m /= i;
            }
        }
        if (m > 1) p[cnt++] = m;
    }
    
    ll solve(ll x) {
        ll len = 1ll << cnt;
        ll ans = 0;
        for (ll i = 1; i < len; i++) {
            int f = 0;
            ll tmp = 1;
            for (ll j = 0; j < cnt; j++) {
                if (i & (1ll << j)) {
                    f++;
                    tmp *= p[j];
                }
            }
            if (f & 1) ans += x / tmp;
            else ans -= x/ tmp;
        }
        return ans;
    }
    
    int main() {
        int T;
        ll a, b;
        scanf("%d", &T);
        int kase = 1;
        while (T--) {
            cnt = 0;
            scanf("%lld%lld%lld", &a, &b, &n);
            init(n);
            printf("Case #%d: %lld
    ", kase++, (b - a + 1) - (solve(b) - solve(a - 1)));
        }
        return 0;
    }
    View Code

    而HDU4407 这题问的是区间的互质的数的和。 其实是差不多的,只不过把个数变成求和。对于分解质因数后的每个质数p,其倍数p,2p,3p.....都是与给定的数不互质的数,容斥即可。

    注意 对于询问1 可以开一个map表示 a->b 的关系。每次for一遍就行。

    ll a[maxn];
    int cnt;
    
    ll n, m;
    
    map<ll, ll> mp;
    ll x, y, z;
    
    ll gcd(ll a, ll b) {
        return b == 0 ? a : gcd(b, a % b);
    }
    
    void init(ll x) {
        cnt = 0;
        for (ll i = 2; i * i <= x; i++) {
            if (x % i == 0) {
                a[cnt++] = i;
                while (x % i == 0) x /= i;
            }
        }
        if (x > 1) a[cnt++] = x;
    }
    
    ll solve(ll x) {
        ll ans = 0;
        for (ll i = 1; i < (1ll << cnt); i++) {
            ll sum = 1;
            int byte = 0;
            for (int j = 0; j < cnt; j++) {
                if (i & (1ll << j)) {
                    byte++;
                    sum *= a[j];
                }
            }
            if (byte & 1) ans += (sum + x / sum * sum) * (x / sum )/2;
            else ans -= (sum + x / sum * sum) * (x / sum) /2;
        }
        return ans;
    }
    
    int main() {
        int T;
        scanf("%d", &T);
        int k;
        while (T--) {
            mp.clear();
            scanf("%lld%lld", &n, &m);
            for (int i = 0; i < m; i++) {
                scanf("%d", &k);
                if (k == 2)  scanf("%lld%lld", &x, &y), mp[x] = y;
                else {
                    scanf("%lld%lld%lld", &x, &y, &z);
                    init(z);
                    ll res = (y - x + 1)* (x + y) / 2 - (solve(y) - solve(x - 1));
                    for (auto it = mp.begin(); it != mp.end(); it++) {
                        if (it->first >= x && it->first <= y) {
                            if (gcd(it->first, z) == 1) res -= it->first;
                            if (gcd(it->second, z) == 1) res += it->second;
                        }
                    }
                    printf("%lld
    ", res);
                }
            }
        }
    }
    View Code
  • 相关阅读:
    【leetcode】Edit Distance (hard)
    【leetcode】 Interleaving String (hard)
    【leetcode】Regular Expression Matching (hard) ★
    【leetcode】Wildcard Matching(hard) ★ 大神太牛了
    【leetcode】 Longest Valid Parentheses (hard)★
    【leetcode】 Scramble String (hard)★
    【leetcode】Maximal Rectangle (hard)★
    【leetcode】 Unique Binary Search Trees (middle)☆
    【计算机网络】应用层1
    【leetcode】Minimum Path Sum(easy)
  • 原文地址:https://www.cnblogs.com/hznumqf/p/13233225.html
Copyright © 2020-2023  润新知