题目链接:
HDU 4135 Co_prime
题意:
求区间
[A,B]
中和
n
互素的数个数?
数据范围:
分析:
我们将
n
进行素因子分解为
例如:
[1,10]
中是
2
的倍数的数字个数是:
[1,10]
中是
3
的倍数的数字个数是:
可以发现是
2∗3=6
的倍数的数字被多算了一次,所以还要减去是
6
的倍数的数字个数
综上:
[1,10]
中和
12
不互素的数字个数是:
5+3−1=7
,那么互素的数字个数就是:
10−7=3
.
以上推广可得:
选择素因子 num 个相乘,得到 mul ,计算 [1,r] 中和 n 不互素的数字个数是根据
num 的奇偶性:奇加偶减, rmul
参考了Acdremers的博客Orz。。。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cmath>
#include <ctime>
#include <cassert>
#include <vector>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
vector<ll> fac;
void GetFactor(int n)
{
fac.clear();
for(ll i = 2; i * i <= n; ++i) {
if(n % i == 0) {
fac.push_back(i);
while(n % i == 0) n /= i;
}
}
if(n > 1) fac.push_back(n);
}
/*
ll solve(ll A, int n)
{
ll ans = 0;
int total = fac.size();
for(ll i = 1; i < (1 << total); ++i) { //用二进制位表示该位上对应编号的素因子是否选择
int bits = 0;
ll res = 1;
for(int j = 0; j < total; ++j) {
if(i & (1 << j)) { //如果选择了第j个素因子
bits++;
res *= fac[j];
}
}
if(bits & 1) ans += A / res; //选择的素因子个数为奇数个
else ans -= A / res;
}
return A - ans;
}
*/
ll ans;
void dfs(int cur, int num, ll mul, ll A)
{
if(cur == fac.size()) {
if(num & 1) ans -= A / mul;
//A / mul 是最大公约数是mul的数字个数,ans求的是互素数个数
else ans += A / mul;
return;
}
dfs(cur + 1, num, mul, A);
dfs(cur + 1, num + 1, mul * fac[cur], A);
}
int main()
{
int T, n, cases = 0;
ll A, B;
scanf("%d", &T);
while(T--) {
scanf("%lld%lld%d", &A, &B, &n);
GetFactor(n);
ans = 0;
dfs(0, 0, 1, B);
ll res = ans;
ans = 0;
dfs(0, 0, 1, A - 1);
printf("Case #%d: %lld\n", ++cases, res - ans);
//printf("Case #%d: %lld\n", ++cases, solve(B, n) - solve(A - 1, n));
}
return 0;
}