href{http://www.lydsy.com/JudgeOnline/problem.php?id=1101}{BZOJ 1101 [POI2007]Zap}
这种形式的式子在之前的文章中出现过不少。
将题目中的式子反演化简到最后会得到一个式子:
egin{equation}
ans=sum_{d}^{lfloor frac{n}{k}
floor}mu(d)lfloor frac{n}{kd}
floor lfloorfrac{m}{kd}
floor
end{equation}
par 然后按照之前的思路,求莫比乌斯函数前缀和和枚举除法取值可以通过这道题。
egin{lstlisting}[language={C++}]
#include<iostream>
#include<cstdio>
#define N 50005
using namespace std;
typedef long long ll;
int tot;
int mu[N];
int sum[N];
bool mark[N];
int prime[N];
void getmu(int n){
int i,j;
mu[1]=1;
for(i=2;i<=n;i++){
if(!mark[i]){
prime[++tot]=i;
mu[i]=-1;
}
for(j=1;prime[j]*i<=n;j++){
mark[prime[j]*i]=1;
if(i%prime[j]==0){
mu[prime[j]*i]=0;
break;
}
mu[prime[j]*i]=-mu[i];
}
}
for(int i=1;i<=n;++i)
sum[i]=sum[i-1]+mu[i];
}
ll query(int n,int m,int k){
m=m/k,n=n/k;int last;
ll ans=0;
for(ll i=1;i<=n;i=last+1){
last=min(n/(n/i),m/(m/i));
ans+=(n/i)*(m/i)*(sum[last]-sum[i-1]);
}
return ans;
}
int main(){
getmu(N);
int n,m,k;
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&m,&k);
if(n>m)swap(n,m);
printf("%lld
",query(n,m,k));
}
return 0;
}
end{lstlisting}
subsection{例题2:}
href{https://www.hackerrank.com/challenges/gcd-product/problem}{GCD Product}
这个网站{color{blue} hackerrank}还是不错的.
题目大意:求$$prod_{i=1}^{n}prod_{j=1}^m(i,j)$$
par 那么又要开始推式子了
egin{align}
ext{设}f(d)=&sum_{i=1}^nsum_{j=1}^mleft[ (i,j)=d
ight]
=&sum_{i=1}^{lfloor frac{n}{d}
floor}mu(i)lfloor frac{n}{id}
floor lfloor frac{m}{id}
floor
ext{带入原式可得,}
ans=&prod_{d=1}^nd^{f(d)}
ans=&prod_{d=1}^nd^{sum_{i=1}^{lfloor frac{n}{d}
floor}mu(i)lfloor frac{n}{id}
floor lfloor frac{m}{id}
floor}
ext{令}T=&id,
ans=&prod_{T=1}^n(prod_{d|T}d^{mu(frac{T}{d})})^{lfloor frac{n}{T}
floor lfloor frac{m}{T}
floor}
ext{设}g(T)=&prod_{d|T}d^{mu(frac{T}{d})}
end{align}
我们需要在线性的时间内求出(g(T)),
观察得知(g(T))有以下性质,
egin{equation}
g(T)=egin{cases}
1, &T=1
p, &T=p^q
1, &others
end{cases}
end{equation}
然后枚举每一个质数的整数幂,复杂度(Theta(n)),
总复杂度(Theta (n+sqrt{n}log(n)))