POI2007 ZAP-Queries
Statement
求 ∑ i = 1 a ∑ j = 1 b [ gcd ( a , b ) = d ] \sum_{i=1}^a\sum_{j=1}^b[\gcd(a,b)=d] ∑i=1a∑j=1b[gcd(a,b)=d]
Solution
设
f
(
d
)
=
∑
i
=
1
N
∑
j
=
1
M
[
gcd
(
i
,
j
)
=
d
]
f(d)=\sum_{i=1}^N\sum_{j=1}^M[\gcd(i,j)=d]
f(d)=∑i=1N∑j=1M[gcd(i,j)=d]
g
(
d
)
=
∑
d
∣
d
′
f
(
d
′
)
=
∑
i
=
1
N
∑
j
=
1
M
[
gcd
(
i
,
j
)
∣
d
]
=
∑
i
=
1
N
∑
j
=
1
M
[
i
∣
d
]
[
j
∣
d
]
=
∑
i
=
1
N
[
i
∣
d
]
∑
j
=
1
M
[
j
∣
d
]
=
∑
i
=
1
N
[
i
∣
d
]
⌊
M
d
⌋
=
⌊
N
d
⌋
⌊
M
d
⌋
\begin{aligned}g(d)&=\sum_{d|d'}f(d')\\ &=\sum_{i=1}^N\sum_{j=1}^M[\gcd(i,j)|d]\\ &=\sum_{i=1}^N\sum_{j=1}^M[i|d][j|d]\\ &=\sum_{i=1}^N[i|d]\sum_{j=1}^M[j|d]\\ &=\sum_{i=1}^N[i|d]\lfloor\frac{M}{d}\rfloor\\ &=\lfloor\frac{N}{d}\rfloor\lfloor\frac{M}{d}\rfloor \end{aligned}
g(d)=d∣d′∑f(d′)=i=1∑Nj=1∑M[gcd(i,j)∣d]=i=1∑Nj=1∑M[i∣d][j∣d]=i=1∑N[i∣d]j=1∑M[j∣d]=i=1∑N[i∣d]⌊dM⌋=⌊dN⌋⌊dM⌋
于是
f
(
d
)
=
∑
d
∣
d
′
μ
(
d
′
d
)
g
(
d
′
)
f(d)=\sum_{d|d'}\mu(\frac{d'}{d})g(d')
f(d)=∑d∣d′μ(dd′)g(d′).
则 A n s = f ( d ) = ∑ d ∣ d ′ μ ( d ′ d ) ⌊ N d ′ ⌋ ⌊ M d ′ ⌋ = ∑ t = 1 min { N d , M d } μ ( t ) ⌊ N t d ⌋ ⌊ M t d ⌋ Ans=f(d)=\sum_{d|d'}\mu(\frac{d'}{d})\lfloor\frac{N}{d'}\rfloor\lfloor\frac{M}{d'}\rfloor=\sum_{t=1}^{\min\{\frac{N}{d},\frac{M}{d}\}}\mu(t)\lfloor\frac{N}{td}\rfloor\lfloor\frac{M}{td}\rfloor Ans=f(d)=∑d∣d′μ(dd′)⌊d′N⌋⌊d′M⌋=∑t=1min{dN,dM}μ(t)⌊tdN⌋⌊tdM⌋.
- 由引理: ∀ a , b , c ∈ Z , ⌊ a b c ⌋ = ⌊ ⌊ a b ⌋ c ⌋ \forall a,b,c\in Z,\lfloor\frac{a}{bc}\rfloor=\lfloor\frac{\lfloor\frac{a}{b}\rfloor}{c}\rfloor ∀a,b,c∈Z,⌊bca⌋=⌊c⌊ba⌋⌋.
Code
# define Fast_IO std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
# include "unordered_map"
# include "algorithm"
# include "iostream"
# include "cstdlib"
# include "cstring"
# include "cstdio"
# include "vector"
# include "bitset"
# include "queue"
# include "cmath"
# include "ctime"
# include "map"
# include "set"
# define ll long long
# define ld long double
# define rep1(i,a,b) for(ll i=(a);i<=(b);i++)
# define rep2(i,a,b) for(ll i=(b);i>=(a);i--)
# define pii pair<int,int>
# define pll pair<ll,ll>
# define ph push_back
# define pb pop_back
# define eb emplace_back
# define vi vector<int>
# define vll vector<ll>
# define vpi vector<pii >
# define vpll vector<pll >
# define ri(x) scanf("%d",&x)
# define rf(x) scanf("%f",&x)
# define rl(x) scanf("%lld",&x)
# define rd(x) scanf("%lf",&x)
# define rs(s) scanf("%s",s+1)
# define wi(x) printf("%d",x)
# define wl(x) printf("%lld",x)
# define ws(s) printf("%s",s+1)
# define resize(v,x) v.resize(x)
# define all(v) v.begin(),v.end()
# define reverse(v) reverse(all(v))
# define fi first
# define se second
# define lowbit(x) ((x)&(-(x)))
# define repauto(Name,v) for(auto Name:v)
# define Endl "\n"
using namespace std;
template<class I> inline I GCD(I A,I B){return B?GCD(B,A%B):A;}
template<class I> inline I LCM(I A,I B){return A/GCD(A,B)*B;}
template<class I> I Sqrt(I N){
I sqrtN=sqrt(N)-1;
while(sqrtN+1<=N/(sqrtN+1))sqrtN++;
return sqrtN;
}
template<class I> I Pow(I X,I Y,__int128 Mod1=998244353){
static __int128 Ans; Ans=1;
for(;Y;Y>>=1,X=(__int128)X*X%Mod1) if(Y&1) Ans=Ans*X%Mod1;
return Ans;
}
namespace Mu_Class{
int Prime_Cnt;
int *Prime=new int;
int *Mu=new int;
int *Visit=new int;
inline void Init(int N){
static int i,j;
delete Visit; Visit=new int[N+1]();
delete Prime; Prime=new int[N+1]();
delete Mu; Mu=new int[N+1]();
for(Mu[1]=1,i=2;i<=N;i++){
if(!Visit[i]){
Visit[i]=i,Mu[i]=-1;
Prime[++Prime_Cnt]=i;
}for(j=1;j<=Prime_Cnt && Visit[i]>=Prime[j] && Prime[j]<=N/i;j++){
Mu[i*Prime[j]]=Visit[i]==Prime[j]?0:Mu[i]*(-1);
Visit[i*Prime[j]]=Prime[j];
}
}for(i=1;i<=N;i++) Mu[i]+=Mu[i-1];
return;
}
}using namespace Mu_Class;
int T;
int N,M,D;
long long Ans;
int main(){
# ifdef LH_Frank
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
# endif
ri(T);
Init(50000);
while(T--){
ri(N),ri(M),ri(D);
N/=D,M/=D;
Ans=0;
for(int i=1;i<=min(N,M);){
int j=min(N/(N/i),M/(M/i));
Ans+=1LL*(N/i)*(M/i)*(Mu[j]-Mu[i-1]);
i=j+1;
}printf("%lld\n",Ans);
}
return 0;
}