题目链接:GCD
解题思路:一开始搜莫比乌斯反演的时候找到的,结果不会,后来看discuss里面说容斥原理+欧拉函数,那么要求gcd(x, y) = k就可以转化为gcd(x / k, y / k) = 1,那么就是互素的数队。欧拉函数表示的就是小于n并且和n互素的数。所以对于区间[1,a][1, b](a < b)来说, 小于a的部分就是直接加欧拉函数值就可以了,那么大于a小于等于b的部分就要容斥原理。设Q是这个部分的一个数,那么对于区间[1,a],只要里面的数不包含Q的质因数就互素,所以我们要找出来这些数。
设Q = I * J * K 我们要减去[1,a]内I, J, K的倍数,就是(a / I + a / J + a / k),发现里面有些数减多了,就是IJ的倍数,JK的倍数,IK的倍数,所以再加回来,又发现加多了,再减去IJK的倍数。所以我们观察发现由偶数个不同的质因数就要减去,奇数个就要加上,这就是容斥原理
RE原因,一直没看K可以等于0,除0报错
TLE原因,对于每一组数据来说都要重新加一遍欧拉函数和,并且对于每一个数都要sqrt(n)来分解质因数,太慢了,所以就预先打出表来。
WA原因,我之前计算的话总是莫名其妙少1,发现我少算了(1,1) 这个点,我就天真的加了1,一直WA,其实应该把euler[1] = 1,这样就对了,但是我的程序一直都没有计算过(1,1)并且所有数据除了k=0特判过了,其他的都必须有(1,1),所以不知为什么。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define ll __int64
#define MAX 100100
using namespace std;
bool isPrime[MAX];
int prime[MAX], eulur[MAX], cnt;
vector<int> p[MAX];
ll falei[MAX];
ll ans;
int fa[50], tt;
void init(){
ans = 0;
}
void Eulur(){
int i, j, k;
falei[1] = eulur[1] = 1;
for(i = 2; i < MAX; i++){
if(!isPrime[i]){
prime[cnt++] = i;
eulur[i] = i - 1;
p[i].push_back(i);
}
for(j = 0; j < cnt && i * prime[j] < MAX; j++){
isPrime[i * prime[j]] = true;
if(i % prime[j] == 0){
eulur[i * prime[j]] = eulur[i] * prime[j];
for(k = 0; k < p[i].size(); k++){
p[i * prime[j]].push_back(p[i][k]);
}
break;
}
else{
eulur[i * prime[j]] = eulur[i] * (prime[j] - 1);
for(k = 0; k < p[i].size(); k++){
p[i * prime[j]].push_back(p[i][k]);
}
p[i * prime[j]].push_back(prime[j]);
}
}
falei[i] = falei[i - 1] + eulur[i];
}
eulur[1] = 1;
}
int get(int x, int y){
int i, j, k, ret = 0;
for(i = 1; i < (1 << p[x].size()); i++){
int tmp = i, sum = 1, amt = 0;
j = 0;
while(tmp){
if(tmp & 1){
sum *= p[x][j];
amt++;
}
tmp >>= 1;
j++;
}
if(sum <= y && sum != 0){
ret += y / sum * (amt % 2 ? 1 : -1);
}
}
return y - ret;
}
int main(){
int i, j, k;
int a, b, c, d, e;
int t, cas = 1;
Eulur();
scanf("%d", &t);
while(t--){
scanf("%d%d%d%d%d", &a, &b, &c, &d, &e);
init();
if(e == 0){
printf("Case %d: %d\n", cas++, 0);
continue;
}
b /= e, d /= e;
a = min(b, d), c = max(b, d);
ans += falei[a];
for(i = a + 1; i <= c; i++){
ans += get(i, a);
}
printf("Case %d: %I64d\n", cas++, ans);
}
return 0;
}