比較好的資源只是可能會轉很久
就是對於積性函數求前綴和。
構造出一個滿足對於任意質數的積性函數。
那麼設,注意這裏是狄利克雷卷積意義下的除法。
有
考慮(是積性函數所以)
所以
又因爲是兩個積性函數的商也是一個積性函數。
所以一定能表示成的形式(也叫),如果我們需要不算重,那麼就讓不含平方因子即可。
積分一下
所以的數量是的。
因爲
又因爲只有根號個地方有值,我們只需要快速求的前綴和即可。
至於快速求的個單點值,可以利用積性函數的性質快速求(猜結論,這個步驟和min25篩一樣)的值然後求出的單點值。
#include<bits/stdc++.h>
#define LL long long
#define mod 1000000007
using namespace std;
LL n;
int K;
#define maxn 4000006
int pr[maxn],vis[maxn],cnt_pr,mu[maxn],mp[maxn];
int ar[maxn],usd[maxn],pw[maxn],pw2[maxn],inv[22],S[22][22];
LL Cube(LL a){ return a * a * a; }
LL sqr(LL a){ return a * a; }
int Pow(int b,int k){ int r=1;for(;k;k>>=1,b=1ll*b*b%mod) if(k&1) r=1ll*r*b%mod; return r; }
int calc(LL n){
static int ans[maxn]={},usd[maxn]={};
n %= mod;
if(n < maxn && usd[n]) return ans[n];
int r = 0;
for(int i=1,s=n+1;i<=K;i++){
s = 1ll * s * (n+1-i) % mod;
r = (r + 1ll * S[K][i] * s % mod * inv[i+1]) % mod;
}
if(n < maxn) usd[n] = 1 , ans[n] = r;
return r;
}
int main(){
freopen("2.in","r",stdin);
scanf("%lld%d",&n,&K);
mu[1] = mp[1] = pw[1] = pw2[1] = inv[0] = inv[1] = 1;
for(int i=2;1ll*i*i<=n;i++){
if(!vis[i]) mu[i] = -1 , pr[cnt_pr++] = i , mp[i] = i;
for(int j=0;sqr(pr[j]*i)<=n;j++){
vis[pr[j] * i] = 1;
mp[pr[j] * i] = pr[j];
if(i % pr[j] == 0){
mu[i * pr[j]] = 0;
break;
}
mu[i * pr[j]] = -mu[i];
}
pw[i] = Pow(i,K) , pw2[i] = pw[i] * 1ll * pw[i] % mod;
}
for(int i=2;i<=K+1;i++)
inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
S[0][0] = 1;
for(int i=1;i<=K;i++)
for(int j=1;j<=i;j++)
S[i][j] = (S[i-1][j-1] + 1ll * S[i-1][j] * j) % mod;
int ans = 0;
for(int i=1;Cube(i)<=n;i++) if(mu[i]){
for(int j=1,LIM=floor(sqrt(n/Cube(i)));j<=LIM;j++){
ar[0] = 0;
int sm = 1;
for(int k=i;k>1;k/=mp[k])
if(!usd[mp[k]])
ar[++ar[0]] = mp[k] , sm = 1ll * sm * (pw[mp[k]] - pw2[mp[k]]) % mod , usd[mp[k]] = 1;
for(int k=j;k>1;k/=mp[k])
if(!usd[mp[k]])
ar[++ar[0]] = mp[k] , sm = 1ll * sm * (pw[mp[k]] - pw2[mp[k]]) % mod , usd[mp[k]] = 1;
ans = (ans + 1ll * sm * calc(n / Cube(i) / sqr(j))) % mod;
for(int k=1;k<=ar[0];k++)
usd[ar[k]] = 0;
}
}
printf("%d\n",(ans+mod)%mod);
}