题意:
给定a,b,n,要求求出a~b区间内与n互质的数的对数。
思路:
乍一看是到欧拉函数的题目(终于不是欧拉函数假扮最大公约数了),可是仔细一想这里的坑:n的数据范围虽然比a、b要大,可是n确实有可能会小于a、b呀,欧拉原理只能求小于n的与n互质的数字的个数,即这里欧拉函数失效了。
所以正确的思路是,容斥原理。
因为[a,b] = [1,b]-[1,a-1],那么同时算出1~b内与n不互质的数的个数和1~a-1内与n不互质的数的个数,两者相减即可。
容斥原理利用的dfs来做,唉唉,看了一会儿dfs的例题,会了一点点,这里终于没有原来那么痛苦了,但是还是有点迷糊
代码:
#include <stdio.h>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1005;
ll a, b, n, cnt, num[N], ansa, ansb;
//求出所有的质因子,并存储到数组里面
void euler(ll n)
{
for(int i = 2; i*i <= n; i++)
{
if(n%i == 0)
{
num[cnt++] = i;
while(n%i == 0)
n /= i;
}
}
if(n > 1) num[cnt++] = n;
}
//最大公约数
ll gcd(ll a, ll b)
{
if(b == 0) return a;
return gcd(b, a%b);
}
//最小公倍数
ll lcm(ll a, ll b)
{
return a*b/gcd(a, b);
}
//利用dfs实现容斥原理
void dfs(ll th, ll now, ll step)
{
if(step > cnt) return;
//n的now因子和第th个因子的最小公倍数
//他一定是与n不互质的,因为它的因子都是n的
ll LCM = lcm(now, num[th]);
//容斥原理的精髓
//第奇数个要加
if(step&1)
{
ansa += a/LCM;
ansb += b/LCM;
}
//第偶数个要减
else
{
ansa -= a/LCM;
ansb -= b/LCM;
}
//接下来选下面的数,层数++,
for(ll i = th+1; i < cnt; i++)
dfs(i, LCM, step+1);
}
int main()
{
int t, Case = 1;
scanf("%d", &t);
while(t--)
{
cnt = 0;
ansa = ansb = 0;
scanf("%lld%lld%lld", &a, &b, &n);
a-=1;
euler(n);//求出n的质因子
//cut为质因子的个数
for(int i = 0; i < cnt; i++)
{
//第i个因子选的是num[i]
//step是深搜层数,一共最多选cut个,所以最多有cut层,等于的话就return了。
dfs(i, num[i], 1);
}
printf("Case #%d: %lld\n", Case++, (b-a) - (ansb-ansa));
}
return 0;
}