题目传送门
分析:
反正都是看博客写的,直接上链接,写得很好
OrzOrzOrz
这题可以用来复习一下杜教筛
列两个公式记一下:
(F(n)=sum_{i=1}^{n}mu(i)=1-sum_{i=2}^{n}F(lfloorfrac{n}{i} floor))
(G(n)=sum_{i=1}^{n}varphi(i)=frac{n(n+1)}{2}-sum_{i=2}^{n}G(lfloorfrac{n}{i} floor))
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<queue>
#include<algorithm>
#include<vector>
#include<map>
#include<ctime>
#include<set>
#define maxn 200005
using namespace std;
inline long long getint()
{
long long num=0,flag=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
return num*flag;
}
int n,m,K;
long long pri[maxn],mu[maxn],cnt;
int np[maxn],prik[maxn],cntk;
long long f[2005],ans;
map<long long,long long>Mu;
map<long long,long long>G[11];
inline int gcd(int p,int q)
{return q?gcd(q,p%q):p;}
inline void init()
{
mu[1]=1;
for(int i=2;i<maxn;i++)
{
if(!np[i])pri[++cnt]=i,mu[i]=-1;
for(int j=1;j<=cnt&&i*pri[j]<maxn;j++)
{
np[i*pri[j]]=1;
if(i%pri[j]==0)break;
mu[i*pri[j]]=-mu[i];
}
}
for(int i=1;i<maxn;i++)mu[i]+=mu[i-1];
for(int i=1;i<=K;i++)f[i]=f[i-1]+(gcd(i,K)==1);
}
inline long long getf(int x){return (x/K)*f[K]+f[x%K];}
inline long long getmu(int x)
{
if(x<maxn)return mu[x];
if(Mu.count(x))return Mu[x];
long long tmp=1;
for(int i=2,j;i<=x;i=j+1)
j=x/(x/i),tmp-=getmu(x/i)*(j-i+1);
return Mu[x]=tmp;
}
inline long long getg(int x,int y)
{
if(!x)return getmu(y);
if(y<=1)return y;
if(G[x].count(y))return G[x][y];
return G[x][y]=getg(x-1,y)+getg(x,y/prik[x]);
}
int main()
{
n=getint(),m=getint(),K=getint();
init();
for(int i=1;i<=cnt&&pri[i]<=K;i++)if(K%pri[i]==0)prik[++cntk]=pri[i];
for(int i=1,j;i<=min(n,m);i=j+1)
{
j=min(n/(n/i),m/(m/i));
ans+=(getg(cntk,j)-getg(cntk,i-1))*(n/i)*getf(m/i);
}
printf("%lld
",ans);
}