Luogu P4450 雙親數
阿新 • • 發佈:2021-07-21
Description:
給定 \(A,B,d\) ,求滿足$1\le a\le A,1\le b\le B $ 且 \(\gcd(a,b)=d\) 的數對數
Solution
考慮莫比烏斯反演
原式可化為
根據套路,我們先給兩邊除以 \(d\),化成
\[\sum_{i=1}^{\left\lfloor\tfrac A d\right\rfloor}\sum_{j=1}^{\left\lfloor\tfrac B d\right\rfloor}\gcd(i,j)=1 \]為什麼要化成這個形式呢?
因為根據莫比烏斯函式的性質
這個式子可以化成
\[\sum_{i=1}^{\left\lfloor\tfrac A d\right\rfloor}\sum_{j=1}^{\left\lfloor\tfrac B d\right\rfloor}\sum_{k\mid \gcd(i,j)} \mu(k) \]我們考慮交換列舉順序,先列舉 \(d\),原式就可以化成
\[\sum_{k=1}^{\min(\frac A d,\frac B d)} \mu(k)\sum_{i=1}^{\left\lfloor\tfrac A d\right\rfloor}\sum_{j=1}^{\left\lfloor\tfrac B d\right\rfloor} [k\mid\gcd(i,j)] \]\[\sum_{k=1}^{\min(\frac A d,\frac B d)}\mu(k)\left\lfloor\tfrac A {kd}\right\rfloor\left\lfloor\tfrac B {kd}\right\rfloor \]對於這個式子,\(\mu\)
Code
/*If you are full of hope,you will be invincible*/ #include <ctime> #include <cstdio> #include <random> #include <cstring> #include <iostream> #include <algorithm> #include<ext/pb_ds/assoc_container.hpp> #include<ext/pb_ds/hash_policy.hpp> #include<ext/pb_ds/priority_queue.hpp> #define ri register int typedef long long ll; std::mt19937 hpy(time(nullptr)+(unsigned long long)(new char)); namespace IO{ constexpr int HL=1<<20; char buf[HL],*t1=buf,*t2=buf; #ifndef ONLINE_JUDGE #define getc() getchar() #else #define getc() t1==t2&&(t2=(t1=buf)+fread(buf,1,HL,stdin),t1==t2)?EOF:*t1++ #endif inline int read(){static int an,f;an = 0,f = 1;static char ch;ch=getc(); while(!isdigit(ch))ch=='-'?f=-1:1,ch=getc(); while(isdigit(ch))an=(an<<3)+(an<<1)+(ch^48),ch=getc(); return an*f;} char buff[HL],*T=buff; void flush(){fwrite(buff,1,T-buff,stdout);T=buff;} inline void putc(char ch){if(T==buff+HL)flush();*T++=ch;} template<typename Tp> inline void print(Tp x){if(x<0)putc('-'),x=-x;if(!x)return putc('0'),void(); static int st[20],tp;while(x)st[++tp]=x%10,x/=10;while(tp)putc(st[tp]^48),--tp;} } using IO::read; using IO::print; using IO::putc; constexpr int inf = 0x3f3f3f3f,N = 1e6 + 10; int vis[N],n,m,cnt; ll pri[N],sum[N],mu[N]; inline void Sieve() { mu[1] = 1; for(ri i = 2;i <= N;++i) { if(!vis[i]) vis[i] = 1,pri[++cnt] = i,mu[i] = -1; for(ri j = 1;j <= cnt && i*pri[j] <= N;++j) { vis[i*pri[j]] = 1; if(i%pri[j] == 0) break; mu[i*pri[j]] = -mu[i]; } }//線性篩μ for(ri i = 1;i <= N;++i) sum[i] = mu[i] + sum[i-1];//用字首和處理 } ll Solve(int a,int b,int d){ int mx = std::min(a,b); ll ans = 0; for(ri l = 1,r;l <= mx;l = r + 1) {//整除分塊 r = std::min(a/(a/l),b/(b/l)); ans += (sum[r]-sum[l-1])*(1ll*a/(1ll*l*d)) * (1ll*b/(1ll*l*d)); } return ans; } int main() { Sieve(); int a=read(),b=read(),d=read(); print(Solve(a,b,d)); return IO::flush(),0; }