标签:
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4135
题意:给一个区间[a,b],再给你一个数n,求在这个区间[a,b]中与n互质的数的个数。
思路:这是一道数学题,如果数据范围不大的话可以直接套用欧拉函数,但是数据范围给得很大。所以用容斥原理来做。
具体思路就是计算[1,a]中与n非互质的数的个数以及[1,b]中与n非互质的数的个数,然后用上限减掉非互质的数的个数,之后作差即可。首先分解n的质因数,接着用一个变量的二进制表示质因数中1的数量,当这个变量是偶数的时候就加,奇数的话就减,因为重复计算了(详解见书《挑战程序设计竞赛P297》)。代码如下:
#include <iostream> #include <cstdio> #include <vector> #include <cmath> using namespace std; typedef long long LL; vector<LL> v; LL a, b; LL n; void init() { v.clear(); scanf("%I64d %I64d %I64d", &a, &b, &n); LL nn = (LL)sqrt(n) + 1; for(int i = 2; i < nn; i++) { if(n % i == 0) { v.push_back(i); while(n % i == 0) { n /= i; } } } if(n > 1) { v.push_back(n); } } LL solve(LL x, LL y) { LL ans; LL m ,cnt; LL s = 1 << v.size(); for(int i = 1; i < s; i++) { m = 1; cnt = 0; for(int j = 0; j < v.size(); j++) { if(i & (1 << j)) { m *= v[j]; cnt++; } } if(cnt & 1) { ans += x / m; } else { ans -= x / m; } } return x - ans; } int main() { int t; int kase = 1; scanf("%d", &t); while(t--) { init(); LL l, r; l = solve(a-1, n); r = solve(b, n); cout << l << " " << r; cout << "Case #" << kase++ << ": " << r - l << endl; } }
标签:
原文地址:http://www.cnblogs.com/vincentX/p/4736656.html