HDOJ 1695 GCD

来源:互联网 发布:游戏编程软件拼音 编辑:程序博客网 时间:2024/05/16 09:13

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1695

题意:求出在1~X中的任意一个数和1~Y中的任意一个数的最大公约数是K的对数,要求像5-7,7-5算是一种。

首先先来分析,要想两个数最大公约数是K,那么首先必须得是K的倍数才行,我们直接把X,Y都除以一个K,这样我们就从1开始遍历的都是K的倍数,并没有改变结果,但是把搜索范围大大的缩小了。

改变了范围之后我们再来分析,现在我要求的就是1~X中的任意一个数和1~Y中的任意一个数的最大公约数为1了,那么也就是说我们要找到任意一个x在1~Y中和其互质的个数,对于求互质的个数,我们采取容斥原理(不懂的同学欢迎观看小编另一篇博客)。由于我们不能重复,所以我们可以限定x < y。

#include <cstdio>#include <cstring>#include <vector>#include <algorithm>using namespace std;#define N 100005typedef long long LL;vector<int> x[N];bool is[N];void prime(){    memset(is, false, sizeof(is));    for(int i=0; i<N; i++) x[i].clear();    for(int j=2; j<N; j+=2) x[j].push_back(2);    for(int i=3; i<N; i+=2)        if(!is[i])            for(int j=i; j<N; j+=i){                is[j] = true;                x[j].push_back(i);            }}int solve(int u, int s, int w){    int cnt = 0, v = 1;    for(int i=0; i<x[w].size(); i++)        if ((1<<i) & s){            cnt++;            v *= x[w][i];        }    int all = u/v;    if(cnt % 2 == 0) return -all;    else return all;}int main(){    prime();    int T, a, b, c, d, k;    scanf("%d", &T);    for(int cas=1; cas<=T; cas++){        scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);        if(k == 0){            printf("Case %d: 0\n", cas);            continue;        }        b /= k, d /= k;        if(b > d) swap(b,d);        LL ans = 0;        for (int i=1; i<=d; i++){            k = min(i, b);            ans += k;            for(int j=1; j<(1<<x[i].size()); j++)                ans -= solve(k, j, i);        }        printf("Case %d: %I64d\n", cas, ans);    }    return 0;}


0 0