求区间 之间与 互质的数的个数 ,
将 分解质因数, 得出 个不同的质因数, 存到 数组中.
利用 容斥 计算 中与不互质的数的数量 , 互质的数量则为 .
使用 的答案再 容斥 一下就可以了 .
- 在容斥找 时需要 求解 , 不能莽乘.
- DFS容斥时需要 判断是否一个数都没有选.
部分:
void DFS(int k, bool opt, int p_sum, const int &x){
if(k == cnt+1){
if(p_sum == 1) return ;
if(!opt) Tmp_1 -= x/p_sum;
else Tmp_1 += x/p_sum;
return ;
}
DFS(k+1, opt^1, Lcm(p_sum, p[k]), x);
DFS(k+1, opt, p_sum, x);
}
按以上解法, 将 换成 就 了, 好奇怪.
症结 ↑
二进制枚举状态部分:
for(reg int i = 1; i < 1<<cnt; i ++){
int p_sum = 1;
int p_cnt = 0;
for(reg int j = 1; j <= cnt; j ++)
if((1<<j-1) & i) p_cnt ++, p_sum = Lcm(p_sum, p[j]);
if(p_cnt & 1) Tmp_1 += x/p_sum;
else Tmp_1 -= x/p_sum;
}
return x-Tmp_1;
没什么好说的.
#include<cstdio>
#include<cctype>
#define reg register
typedef long long ll;
const int maxn = 105;
int Test_Cnt;
int N;
int cnt;
int p[maxn];
ll Tmp_1;
ll L;
ll R;
int Gcd(int a, int b){ return !b?a:Gcd(b, a%b); }
int Lcm(int a, int b){ return a/Gcd(a, b)*b; }
ll Calc(ll x){
if(!x) return 0;
Tmp_1 = 0;
for(reg int i = 1; i < 1<<cnt; i ++){
int p_sum = 1;
int p_cnt = 0;
for(reg int j = 1; j <= cnt; j ++)
if((1<<j-1) & i) p_cnt ++, p_sum = Lcm(p_sum, p[j]);
if(p_cnt & 1) Tmp_1 += x/p_sum;
else Tmp_1 -= x/p_sum;
}
return x-Tmp_1;
}
void Work(){
scanf("%lld%lld%d", &L, &R, &N);
cnt = 0;
for(reg int d = 2; d*d <= N; d ++)
if(N % d == 0){
p[++ cnt] = d;
while(N%d == 0) N /= d;
}
if(N > 1) p[++ cnt] = N; //Attention
printf("Case #%d: %lld
", ++ Test_Cnt, Calc(R) - Calc(L-1));
}
int main(){
int T;
scanf("%d", &T);
while(T --) Work();
return 0;
}