HDU-1695 GCD 容斥定理

这题首先要将等式两边除以k,这样在求两边的互质数的个数就是最后的结果了。我们采用的策略就是用小区间的每一个数去匹配大区间的数。但是如果每次都去分解一个数的质因子的话,那么会TLE,因此先预处理出1-100000每个数的质因子再进行计算。

代码如下:

#include <cstring>

#include <cstdlib>

#include <cstdio>

#include <algorithm>

#include <cmath>

using namespace std;



int a, b, c, d, k, rec[300000], idx;



int start[100005], end[100005], S, E;



long long int ret;



void cut(int x)

{

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

    if (x % 2 == 0) {

        rec[++idx] = 2;

        while (x % 2 == 0) { x /= 2; }

    }

    for (int i = 3; i <= LIM; i += 2) {

        if (x % i == 0) {

            rec[++idx] = i;

            while (x % i == 0) { x /= i; }

        }

    }

    if (x != 1) { rec[++idx] = x; }

}



void pre()

{

    idx = 0;

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

        start[i] = idx;

        cut(i);

        end[i] = idx;

    }

}



void dfs(int p, int num, int sign, int &sum, int l, int r)

{

    if (p == E) {

        if (num > 1) {

            sum += sign * (r / num - (l-1) / num);

        }

        return;

    }

    dfs(p+1, num, sign, sum, l, r);

    dfs(p+1, num*rec[p+1], -sign, sum, l, r);

}



int main()

{

    int T, ca = 0, sum, l, r;

    pre();

    scanf("%d", &T);

    while (T--) {

        ret = 0;

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

        printf( "Case %d: ", ++ca);

        if (!k) {

            puts("0");

            continue;

        }

        b /= k, d /= k;

        if (b > d) {

            int t = b;

            b = d;

            d = t;

        }

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

            S = start[i], E = end[i];

            sum = 0;

            l = i, r = d;

            dfs(S, 1, -1, sum, l, r);

            ret += (r-l+1) - sum;

        }

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

    }

    return 0;

}

你可能感兴趣的:(HDU)