传送门
如果求出
那么 就是答案
有一个结论是
证明(口胡):考虑某一个质因子 ,假设最后在约数中为
令如果 在 中为 ,如果 那么我们在 中填上 ,否则在 中填上
显然 只会在一边出现而且所有的因数考虑完了
如果是 的话考虑一下上面的过程想一想最后是什么数,有:
已经可以 预处理, 查询了,但 较大
考虑一个 的贡献,对所有 都有贡献,于是就可以 预处理, 查询
同理
顺带一提, 可以用线性筛,考虑质数次幂的贡献即可
#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int Mod = 1e9 + 7, N = 1e6 + 5;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Add(int &a, int b){ a = add(a, b); }
int T, n, mu[N], sig[N], Ssig[N];
bool isp[N]; int prim[N], tot;
int Mn[N], vlMn[N], ans[N], f[N], g[N];
void prework(){
n = 1e6;
mu[1] = sig[1] = 1;
for(int i = 2; i <= n; i++){
if(!isp[i]){
prim[++tot] = i;
sig[i] = i+1; mu[i] = Mod-1;
Mn[i] = 1; vlMn[i] = i+1;
}
for(int j = 1; j <= tot; j++){
if(prim[j] * i > n) break;
int k = prim[j] * i; isp[k] = true;
if(i % prim[j] == 0){
Mn[k] = Mn[i]; mu[k] = 0;
vlMn[k] = add(mul(vlMn[i], prim[j]), 1);
sig[k] = mul(vlMn[k], sig[Mn[k]]);
break;
}
Mn[k] = i; vlMn[k] = prim[j]+1;
mu[k] = mul(mu[i], mu[prim[j]]);
sig[k] = mul(sig[i], sig[prim[j]]);
}
}
for(int i = 1; i <= n; i++){
f[i] = mul(mu[i], mul(i,i));
Ssig[i] = add(Ssig[i-1], sig[i]);
g[i] = mul(mul(i, sig[i]), dec(mul(2,Ssig[i]),sig[i]));
}
for(int i = 1; i <= n; i++)
for(int j = 1, up=n/i; j <= up; j++)
Add(ans[i*j], mul(f[i],g[j]));
for(int i = 1; i <= n; i++) Add(ans[i], ans[i-1]);
}
int main(){
prework();
cin >> T; for(int i = 1; i <= T; i++){
scanf("%d", &n); cout << "Case #" << i << ": " << ans[n] << '\n';
} return 0;
}