Description
<span style="font-size:18px;">Given a number N, you are asked to count the number of integers between A and B inclusive which are relatively prime to N.Two integers are said to be co-prime or relatively prime if they have no common positive divisors other than 1 or, equivalently, if their greatest common divisor is 1.The number 1 is relatively prime to every integer.</span>
Input
<span style="font-size:18px;">The first line on input contains T (0 &lt; T &lt;= 100) the number of test cases, each of the next T lines contains three integers A, B, N where (1 &lt;= A &lt;= B &lt;= 10^15) and (1 &lt;=N &lt;= 10^9).</span>
Output
<span style="font-size:18px;">For each test case, print the number of integers between A and B inclusive which are relatively prime to N. Follow the output format below.</span>
Sample Input
<span style="font-size:18px;">2 1 10 2 3 15 5</span>
Sample Output
<span style="font-size:18px;">Case #1: 5 Case #2: 10</span>
Hint
Source
分隔符
题意:
输入三个数:A,B,N,求在A到B之间(包含A,B)有多少个数与N互质。
思路:
类似这道题点击打开链接,首先对N质数分解,求出小于等于A中的数中与N互质的数的个数,再求出小于等于B中的数中与N互质的数的个数,两个数一减,再特判A,就行了。
求小于等于A中的数中与N互质的数的个数用到容斥,把N分解后的质因子一个一个去掉,去多的加回来,用一个dfs枚举每一种情况(2^9左右),奇偶次加减不一样具体分析就可以了。
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
typedef long long LL;
LL Stack[1000],top,Cnt[1000],tmp[1000];
LL ans1,ans2,kk,tt,aa;
void fenjie(LL k)///素数分解
{
top=1;
memset(Cnt,0,sizeof(Cnt));
for(LL i=2;i*i<=k;i++)if(k%i==0){
while(k%i==0)Cnt[top]++,k/=i;
Stack[top++]=i;
}
if(k>1){
Cnt[top]++;
Stack[top++]=k;
}
}
LL q[11];
LL p[11];
void dfs(LL Stack[],int top,int s,int e,int k,LL q[],LL aa,LL &ans1)///dfs遍历质因数的所有情况,进行容斥
{
q[k]=Stack[s];
if(k==e)
{
if(e%2==1)
{
LL te=1;
for(LL i=1;i<=e;i++)
te*=q[i];
LL temp=aa/te;
ans1+=temp;///奇数次加
}
else
{
LL te=1;
for(LL i=1;i<=e;i++)
te*=q[i];
LL temp=aa/te;
ans1-=temp;///偶数次减
}
}
else
{
for(int i=1;i+s<top;i++)
{
k++;
dfs(Stack,top,s+i,e,k,q,aa,ans1);
k--;
}
}
}
LL gcd(LL a,LL b)
{
return b?gcd(b,a%b):a;
}
int main()
{
int n;
int cas=1;
scanf("%d",&n);
while(n--)
{
scanf("%lld%lld%lld",&tt,&aa,&kk);
fenjie(kk);
ans1=0,ans2=0;
for(int e=1;e<top;e++)
for(int i=1;i<top;i++)
{dfs(Stack,top,i,e,1,q,aa,ans2);
dfs(Stack,top,i,e,1,p,tt,ans1);}
LL anss=aa-tt+1+ans1-ans2;
if(gcd(tt,kk)!=1)anss--;
printf("Case #%d: %lld\n",cas++,anss);
}
return 0;
}
二进制枚举做法:
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int MOD=1e9+7;
typedef long long LL;
LL Stack[1000],top,Cnt[1000],tmp[1000];
LL ans,kk;
void fenjie(LL k)///素数分解
{
top=0;
memset(Cnt,0,sizeof(Cnt));
for(LL i=2;i*i<=k;i++)if(k%i==0){
while(k%i==0)Cnt[top]++,k/=i;
Stack[top++]=i;
}
if(k>1){
Cnt[top]++;
Stack[top++]=k;
}
}
LL solve(LL a)
{
LL ans1=0;
for(LL i=1;i<(1<<top);i++)
{
LL sum=0,ans=1;
for(LL j=0;j<top;j++)
if(i&(1<<j))
{
sum++;
ans*=Stack[j];
}
if(sum&1)
ans1+=a/ans;
else
ans1-=a/ans;
}
return ans1;
}
int main()
{
int n;
scanf("%d",&n);
LL A,B,N;
int cas=1;
while(n--)
{
scanf("%lld%lld%lld",&A,&B,&N);
fenjie(N);
LL ans=B-A+1-solve(B)+solve(A-1);
//cout<<solve(A-1)<<" "<<solve(B)<<endl;
printf("Case #%d: %lld\n",cas++,ans);
}
return 0;
}