Loading

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\n", 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\n", res);
            }
        }
    }
}
View Code

 

posted @ 2020-07-03 23:31  MQFLLY  阅读(137)  评论(0编辑  收藏  举报