题目链接
题意
给你三个整数a,b,c求[a,b]区间内与n互质数个数
思路
即求[a,b]区间内与n不互质数个数,即将n进行素数拆分
一个数是某个拆分数的倍数即不互质,如wtf/素数pri 为 1到wtf间与pri不互质的个数)
素数拆分有很多,会重复计数,用容斥原理剔除。
ans = r-(l-1) - ( solve( r ) - solve( l-1 ) )
代码(含两种版本)
递归版
#include <stdio.h>
#define ll long long
ll l, r, num[100], len;
ll dfs(ll n, ll x)
{
ll tmp = 0;
for(ll i = x; i < len; ++i) tmp += n/num[i] - dfs(n/num[i], i+1);
return tmp;
}
int main()
{
ll t, ca = 1, n;
for(scanf("%lld",&t); ca <= t; ++ca)
{
scanf("%lld%lld%lld",&l,&r,&n);
len = 0;
for(ll i = 2; i*i <= n; ++i)
{
if(n%i == 0)
{
num[len++] = i;
while(n%i == 0) n /= i;
}
}
if(n > 1) num[len++] = n;
printf("Case #%lld: %lld\n",ca, r-(l-1) - (dfs(r, 0) - dfs(l-1, 0)));
}
return 0;
}
二进制版本
#include <stdio.h>
#define ll long long
ll l, r, num[100], len;
ll solve(ll n)
{
ll ans = 0;
for(ll i = 1; i < (1ll<<len); ++i)
{
ll tmp = 0, wtf = 1;
for(ll j = 0; j < len; ++j)
{
if((1ll<<j) & i)
{
wtf *= num[j];
tmp ^= 1;
}
}
ans += tmp ? n/wtf : -n/wtf;
}
return ans;
}
int main()
{
ll t, ca = 1, n;
for(scanf("%lld",&t); ca <= t; ++ca)
{
scanf("%lld%lld%lld",&l,&r,&n);
len = 0;
for(ll i = 2; i*i <= n; ++i)
{
if(n%i == 0)
{
num[len++] = i;
while(n%i == 0) n /= i;
}
}
if(n > 1) num[len++] = n;
printf("Case #%lld: %lld\n",ca, r-(l-1) - (solve(r) - solve(l-1)));
}
return 0;
}