杜教筛板子,只要学了并且还会推导就能随便做(除了卡常)。
n,m范围1e10,B范围mod以内,mod9990017。
其实这个mod如此与众不同是在提示你可以卢卡斯。
枚举T=kd
发现实际上是组合数和莫比乌斯函数的狄利克雷卷积。
令
所以目标是F(T)的前缀和。这东西都说了有莫比乌斯函数的卷积,根据套路我们直接卷上一个I。
提示:I函数任何时候取值都是1。
根据杜教筛公式
其中
所以我们要求一个组合数的一列和。这个一列和有个很好推导的公式就是
那公式就弄完了。根据杜教筛预处理最优复杂度证明,预处理的F(直接埃氏筛),然后记忆化搜索。
少取模,多卡常,最烦卡常了。
#include<bits/stdc++.h>
#include<tr1/unordered_map>
using namespace std;
using namespace tr1;
#define in read()
#define LL long long
LL in{
LL cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();
}
while(isdigit(ch)){
cnt=cnt*10ll+ch-48ll;
ch=getchar();
}return cnt;
}
const int mod=9990017;
const int N=(int)pow(1e10,2.0/3);
int F0[N];
unordered_map<LL,int> F;
LL n,m,B; int fac[mod+1],ifac[mod+1];
inline int c(int x,int y){
if(x<y)return 0;
return (LL)fac[x]*ifac[y]%mod*ifac[x-y]%mod;
}
inline int C(int x,int y){
if(x<y)return 0;
return (LL)c(x%mod,y%mod)*((x>=mod)?C(x/mod,y/mod):1)%mod;
}
inline int ksm(int a,int b){
int gu=1;
while(b){
if(b&1)
gu=(LL)gu*a%mod;a=(LL)a*a%mod;b>>=1;
}return gu;
}
inline void prepare(){
fac[0]=1;
for(register int i=1;i<mod;++i)fac[i]=(LL)fac[i-1]*i%mod;
ifac[mod-1]=ksm(fac[mod-1],mod-2);
for(register int i=mod-2;i>=1;i--)ifac[i]=(LL)ifac[i+1]*(i+1)%mod;ifac[0]=1;
for(register int i=1;i<=N;++i)F0[i]=C(i,B);
for(register int i=1;i<=N;++i){
for(register int j=i*2;j<=N;j+=i){
F0[j]=(F0[j]-F0[i]);if(F0[j]<0)F0[j]+=mod;
}
}
for(register int i=1;i<=N;++i)F0[i]=(F0[i-1]+F0[i])%mod;
}
inline int S(LL x){
if(x<=N)return F0[x];
if(F.count(x))return F[x];
int sum=C(x+1,B+1);
for(register LL l=2,r;l<=x;l=r+1){
r=x/(x/l);
sum-=(LL)(r-l+1)*S(x/l)%mod;
if(sum<0)sum+=mod;
}return F[x]=sum;
}
signed main(){
n=in;m=in;B=in;if(n>m)swap(n,m);
prepare();
int ans=0;
for(register LL l=1,r;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
ans=(ans+(LL)(S(r)-S(l-1))%mod*(n/l)%mod*(m/l)%mod)%mod;
}printf("%d", (ans+mod)%mod);
return 0;
}