对于这种与gcd有关的莫比乌斯反演,一般我们都是套路的去设f(d)为gcd(i,j)=d的个数,F(n)为gcd(i,j)=d和d的倍数的个数,然后用莫比乌斯反演,然后整出一个可以整数分块的东西.
等我学完latex再发式子,详情可见luogu题解.
题干:
FGD正在破解一段密码,他需要回答很多类似的问题:对于给定的整数a,b和d,有多少正整数对x,y,满足x<=a,y<=b,并且gcd(x,y)=d。作为FGD的同学,FGD希望得到你的帮助。
代码:
#include<iostream> #include<cstdio> #include<cmath> #include<queue> #include<algorithm> #include<vector> #include<complex> #include<cstring> using namespace std; #define duke(i,a,n) for(int i = a;i <= n;i++) #define lv(i,a,n) for(int i = a;i >= n;i--) #define clean(a) memset(a,0,sizeof(a)) #define mp make_pair #define cp complex<db> #define enter puts("") const long long INF = 1LL << 60; const double eps = 1e-8; typedef long long ll; typedef double db; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < '0' || c > '9') if(c == '-') op = 1; x = c - '0'; while(c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } const int N = 50005; int miu[N],sum[N],tot = 0,che[N],pri[N]; void init() { miu[1] = 1; duke(i,2,N) { if(!che[i]) { pri[++tot] = i; miu[i] = -1; } duke(j,1,tot) { if(i * pri[j] > N) break; che[i * pri[j]] = 1; if(!(i % pri[j])) break; else miu[pri[j] * i] = -miu[i]; } } duke(i,1,N) sum[i] = sum[i - 1] + miu[i]; } int T; int main() { read(T); init(); while(T--) { ll n,m,d,ans = 0; read(n);read(m);read(d); n /= d;m /= d; if(n < m) swap(n,m); for(int i = 1;i <= m;) { int t; t = min(n,min(n / (n / i),m / (m / i))); ans += (sum[t] - sum[i - 1]) * (n / i) * (m / i); i = t + 1; } printf("%lld ",ans); } return 0; }