题意:题目大意是求(a,b)区间与n互质的数的个数
题解:首先求(a,b)区间的个数可以转化成(1,b)间的个数减去(1,a-1)间的个数
然后求互质的个数可以转化成总个数减去不互质的个数
那怎么求不互质的个数呢?首先求出n的质因子
求出质因子的两个算法
1.n的个数不多,但数字大(转自ACM不懈的追求大神的博客)
#include<stdio.h>
int main()
{
__int64 a[100],num,i,n;
while(scanf("%I64d",&n)!=EOF)
{
num=0;
for(i=2;i*i<=n;i++)
{
if(n%i==0)//如果n能整除i
{
a[num++]=i;//用数组a储存因子
while(n%i==0)
n=n/i;
}
}
if(n>1)
a[num++]=n;
for(i=0;i<num;i++)
printf("%I64d ",a[i]);
printf("\n");
}
return 0;
}
第二个:一次求出1~n所有数的质因子,适用于题目中n的个数比较多,但是n不大的
#include<iostream>
#include<vector>
#include<algorithm>
#include<string.h>
using namespace std;
int visited[100010];
vector<int>a[100010];
void init()
{
int i,j;
for(i=0;i<100010;i++)
a[i].clear();//vector的清空
memset(visited,0,sizeof(visited));
for(i=2;i<=100000;i++)
{
if(visited[i]==0)//i是素数这是可以保证的
{
a[i].push_back(i);
for(j=i+i;j<=100000;j+=i)//筛选素数,其实这种方法没以前那种素数法快,但是这里用来求一个数的质因子就比较好了
{
visited[j]=1;
a[j].push_back(i);
}
}
}
}
int main()
{
int i,j;
init();
for(i=0;i<=50;i++)
{
printf("%d:",i);
for(j=0;j<a[i].size();j++)
printf("%d ",a[i][j]);
printf("\n");
}
return 0;
}
但是在处理的过程中会重复的数字会删去多次,比如2,3,的公倍数6
删去2的倍数的时候删去了6,删去3的倍数的时候又删去了6
所以需要利用容斥原理
容斥原理的实现:dfs,队列数组,位运算
1.队列数组实现(转自ACM不懈的追求大神的博客)
#include<iostream>
#include<string.h>
using namespace std;
__int64 a[1000],num;
void init(__int64 n)//求一个数的质因子
{
__int64 i;
num=0;
for(i=2;i*i<=n;i++)
{
if(n%i==0)
{
a[num++]=i;
while(n%i==0)
n=n/i;
}
}
if(n>1)//这里要记得
a[num++]=n;
}
__int64 haha(__int64 m)//用队列数组实现容斥原理
{
__int64 que[10000],i,j,k,t=0,sum=0;
que[t++]=-1;
for(i=0;i<num;i++)
{
k=t;
for(j=0;j<k;j++)
que[t++]=que[j]*a[i]*(-1);
}
for(i=1;i<t;i++)
sum=sum+m/que[i];
return sum;
}
int main()
{
__int64 T,x,y,n,i,sum;
while(scanf("%I64d",&T)!=EOF)
{
for(i=1;i<=T;i++)
{
scanf("%I64d%I64d%I64d",&x,&y,&n);
init(n);
sum=y-haha(y)-(x-1-haha(x-1));
printf("Case #%I64d: ",i);
printf("%I64d\n",sum);
}
}
return 0;
}