利用容斥原理求一个数跟一个区间中互质的数的个数。
可以求的不互质的数的个数,然后用总数减掉就是不互质的数的个数。
求不互质的个数,可以用容斥原理,求出n所有质因子,设为a,b,c,区间l=1,那么与n不互质的数的个数为r/a+r/b+r/c-r/(a*b)-r/(a*c)-r/(b*c)+r/(a*b*c),质因子数量更多的话就用状压dp搞一下,取奇数个因子就加上,偶数个减去,就得到答案。
附代码:
hdu4135
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long int ll;
int cnt;
ll A,B,N;
ll solve(ll n,ll r)
{
cnt=0;
ll p[15];
for (ll i=2;i*i<=n;i++)
{
if (n%i==0)
p[cnt++]=i;
while (n%i==0)
n/=i;
}
if (n>1)
p[cnt++]=n;
int mm=(1<<cnt)-1;
cnt--;
ll ans=0;
for (int i=1;i<=mm;i++)
{
ll pp=1;
int cc=0;
for (int t=0;t<=cnt;t++)
{
int x=(1<<t);
if (x&i)
{
pp*=p[t];
cc++;
}
}
if (cc&1)
ans+=(r/pp);
else
ans-=(r/pp);
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
for (int i=1;i<=T;i++)
{
scanf("%I64d%I64d%I64d",&A,&B,&N);
ll ans=(B-A+1)-solve(N,B)+solve(N,A-1);
printf("Case #%d: %I64d\n",i,ans);
}
}
hdu1695
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
int cnt;
int a,b,c,d,k;
ll solve(ll n,ll r)
{
cnt=0;
ll p[15];
for (ll i=2;i*i<=n;i++)
{
if (n%i==0)
p[cnt++]=i;
while (n%i==0)
n/=i;
}
if (n>1)
p[cnt++]=n;
int mm=(1<<cnt)-1;
cnt--;
ll ans=0;
for (int i=1;i<=mm;i++)
{
ll pp=1;
int cc=0;
for (int t=0;t<=cnt;t++)
{
int x=(1<<t);
if (x&i)
{
pp*=p[t];
cc++;
}
}
if (cc&1)
ans+=(r/pp);
else
ans-=(r/pp);
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
for (int i=1;i<=T;i++)
{
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
if (k==0)
{
printf("Case %d: 0\n",i);
continue ;
}
b/=k;
d/=k;
if (b>d)
{
int t=b;
b=d;
d=t;
}
ll ans=0;
for (int t=1;t<=b;t++)
ans+=(ll)(d-t+1)-solve(t,d)+solve(t,t-1);
printf("Case %d: %I64d\n",i,ans);
}
}