HDU-4407 Sum 容斥定理

对于一个数F,设F = p1^e1*p2^e2...*pn^en 那么[1-N]内与其互质的数和与D = p1*p2*...pn是一致的,因为和F、D互质的数都是不含有他们的素因子的数。对于D这个数求[1-N]内有多少个与其互质的数就可用运用容斥定理来求解了。以6为例,首先计算出与2不互质的数,用等差数列公式能够计算出这些满足于2不互质数的和,接着就加上与3不互质的和,最后再减一次与6不互质的和即可。对于那些改变的数,由于数量不是很多,可以单独拿出来进行处理。

代码如下:

#include<iostream>

#include<cstdio>

#include<cstdlib>

#include<algorithm>

#include<cmath>

#include<queue>

#include<set>

#include<map>

#include<cstring>

#include<vector>

#include<string>

#define MAXN 800

#define LL long long

using namespace std;



int N, M, rec[50];

map<int,int>mp;

bool p[805];

int pri[805], idx;



inline int gcd(int a, int b) {

    return b ? gcd(b, a % b) : a;

}



inline void Getprime() {

    idx = -1;

    for (int i = 2; i <= MAXN; ++i) {

        if (!p[i]) {

            pri[++idx] = i;

        }

        for (int j = 0; i * pri[j] <= MAXN; ++j) {

            p[i*pri[j]] = 1;

            if (i % pri[j] == 0) break;

        }

    } 

}



inline long long cal(int num, int x) {

    if (x == 0) return 0;

    long long ret = 0;

    int cnt = 0, mask;

    int LIM = (int)sqrt(double(num));

    for (int i = 0; pri[i] <= LIM; ++i) {

        if (num % pri[i] == 0) {

            rec[++cnt] = pri[i];

            while (num % pri[i] == 0) {

                num /= pri[i];

            }

        }

        if (num == 1) break;

    }

    if (num != 1) {

        rec[++cnt] = num;

    }

    mask = 1 << cnt;

    for (int i = 1; i < mask; ++i) { 

        int tsum = 0;

        long long yinzi = 1;

        for (int j = 0; j < cnt; ++j) {

            if (i & (1 << j)) {

                ++tsum;

                yinzi *= rec[j+1];

            }

        } 

        if (tsum & 1) {

            long long k = x / yinzi;

            ret += ((yinzi + k * yinzi) * k) >> 1;

        } else {

            int k = x / yinzi;

            ret -= ((yinzi + k * yinzi) * k) >> 1;

        }

    }

    return ret;

}



inline long long SUM(int x) {

    return ((1 + 1LL * x) * 1LL * x) >> 1;

}



int main()

{

    Getprime();

     int T, op, a, b, p;

     map<int,int>::iterator it;

     long long ret;

     scanf("%d", &T);

     while (T--) {

        mp.clear();

        scanf("%d %d", &N, &M);

        for (int i = 1; i <= M; ++i) {

            scanf("%d", &op);

            if (op == 1) { 

                ret = 0;

                scanf("%d %d %d", &a, &b, &p);

                for (it = mp.begin(); it != mp.end(); ++it) {

                    if (it->first != it->second && it->first >= a && it->first <= b) {

                        ret -= gcd(it->first, p) == 1 ? it->first : 0;

                        ret += gcd(it->second, p) == 1 ? it->second : 0;

                    }

                }

                ret += SUM(b) - SUM(a-1) - (cal(p, b) - cal(p, a-1));

                printf("%I64d\n", ret);

            } else {

                scanf("%d %d", &a, &b);

                mp[a] = b;

            }

        }

    }

    return 0;

}

 

你可能感兴趣的:(HDU)