题意
求
∑
d
∣
n
!
∑
i
=
1
m
σ
0
(
d
i
)
\sum_{d|n!}\sum_{i=1}^{m}\sigma_0(di)
∑d∣n!∑i=1mσ0(di)
其中
σ
0
(
n
)
\sigma_0(n)
σ0(n)表示
n
n
n的约数个数。
n
≤
200
n\le 200
n≤200
m
≤
1
0
10
m\le 10^{10}
m≤1010
正解
核心式子: σ 0 ( n m ) = ∑ i ∣ n ∑ j ∣ m [ gcd ( i , j ) = 1 ] \sigma_0(nm)=\sum_{i|n}\sum_{j|m}[\gcd(i,j)=1] σ0(nm)=∑i∣n∑j∣m[gcd(i,j)=1]
考虑 gcd ( i , j ) = 1 \gcd(i,j)=1 gcd(i,j)=1是什么情况:
对于每个质数 p p p, i i i中 p p p的指数为 0 0 0或 j j j中 p p p的指数为 0 0 0。
那么就有: i 中 p 的 指 数 + j 中 i中p的指数+j中 i中p的指数+j中p 的 指 数 + 1 的指数+1 的指数+1种方案。
将不同质数的这个东西乘起来,恰好就是算因数个数的那条式子。
知道这个式子之后往下推,最终会推出一条可以快速算的东西。
不在此赘述。
代码
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 210
#define mo 1000000007
#define ll long long
int n;
ll m;
int p[N],np;
bool inp[N];
int mnp[N];
int e[N];
int D(ll m){
ll s=0;
for (ll i=1;i<=m;++i){
ll d=m/i,j=m/d;
s+=(ll)(j-i+1)*d%mo;
i=j;
}
return s%mo;
}
ll ans;
void dfs(int x,ll k,int mu,int E){
if (x>np){
(ans+=(ll)mu*D(m/k)%mo*E)%=mo;
return;
}
dfs(x+1,k,mu,(ll)E*((e[x]+2)*(e[x]+1)/2)%mo);
if (k*p[x]<=m)
dfs(x+1,k*p[x],mo-mu,(ll)E*((e[x]-1+2)*(e[x]-1+1)/2)%mo);
}
int main(){
// freopen("in.txt","r",stdin);
freopen("divisor.in","r",stdin);
freopen("divisor.out","w",stdout);
scanf("%d%lld",&n,&m);
for (int i=2;i<=n;++i){
if (!inp[i])
p[++np]=i,mnp[i]=np;
for (int j=1;j<=np && i*p[j]<=n;++j){
inp[i*p[j]]=1;
mnp[i*p[j]]=j;
if (i%p[j]==0)
break;
}
}
for (int i=1;i<=n;++i)
for (int j=i;j!=1;j/=p[mnp[j]])
e[mnp[j]]++;
dfs(1,1,1,1);
printf("%lld\n",ans);
return 0;
}