题意:求区间[a,b]中与n互质的数的个数,其中a,b <= 10e15, n <= 10e9
思路:利用容斥原理求得[1,b]和[1,a-1]中n不互质的数的个数,从而间接求得与n互质的数的个数,然后相减
代码如下:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#define ll __int64
#define N 1000000000
#define inf 0x7ffffff
#define eps 1e-9
#define pi acos(-1.0)
#define P system("pause")
using namespace std;
int pri[10000],vis[100000];
int tot = 0,len;
int c[100];
void get_primes()
{
int m = (int)sqrt(N + 0.5);
memset(vis,0,sizeof(vis));
ll i, j;
for(i = 2; i <= m; i++)
if(!vis[i])
{
pri[tot++] = i;
for(j = i*i; j <= m; j+=i)
vis[j] = 1;
}
}
ll cal(ll n)//利用位运算实现容斥原理
{
ll ans = 0;
ll i,j;
for(i = 1; i < (1LL<<len); i++)
{
ll temp = 0,k = 1;
for(j = 0; j < len; j++)
if(i&(1LL<<j)){
temp++;
k *= c[j];
}
if(temp&1)
ans += n/k;
else ans -= n/k;
}
return ans;
}
int main()
{
// ios::sync_with_stdio(false);
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
int n,t,z = 1;
get_primes();
scanf("%d",&t);
while(t--)
{
ll a,b;
int i;
scanf("%I64d%I64d%d",&a,&b,&n);
len = 0;
for(i = 0; i < tot && pri[i]*pri[i] <= n; i++)
{
if(n == 1) break;
if(n%pri[i] == 0)
{
c[len++] = pri[i];
while(n%pri[i] == 0)
n /= pri[i];
}
}
if(n > 1)
c[len++] = n;
printf("Case #%d: ",z++);
printf("%I64d\n",b - cal(b) - (a-1 - cal(a-1)));
}
return 0;
}