Before all
唉又没有时间打 CF,只好事后自己做了。。。
题目大意
定义一个函数 f(i)f(i)f(i) 表示不为 iii 的因子的最小正整数,比如 f(1)=2,f(2)=3,f(4)=3f(1)=2,f(2)=3,f(4)=3f(1)=2,f(2)=3,f(4)=3。现给出一个 n(n≤1016)n(n\le 10^{16})n(n≤1016),求 ∑i=1nf(i)\sum_{i=1}^{n}f(i)∑i=1nf(i) 的值 mod109+7\operatorname{mod} 10^9+7mod109+7。
Solution
从简单开始思考,显然,所有的奇数的 f(i)f(i)f(i) 都是 222。所以我们来考虑偶数。
偶数必然有因子 1,21,21,2,所以我们暂且认为偶数的 f(i)=3f(i)=3f(i)=3。为了接下来分析方便起见,我将偶数及其函数值打成一张表:
iii | 222 | 444 | 666 | 888 | 101010 | 121212 | 141414 | 161616 | 181818 | …\dots… |
---|---|---|---|---|---|---|---|---|---|---|
f(i)f(i)f(i) | 333 | 333 | 444 | 333 | 333 | 555 | 333 | 333 | 444 | …\dots… |
不难看出,每 666 个会出现一个 444,每 121212 个会出现一个 555……
那么这个 666 和 121212 是哪里来的呢?
我们不妨把 f(i)=3f(i)=3f(i)=3 的偶数表示为 222,除此以外的因子都比 333 大的形式。那么 666 就是 2×32\times 32×3,除此以外因子都比 444 大……
所以,我们可以先打表来算这个每一个 f(i)f(i)f(i) 的出现周期。我们需要保证这个值是包含因子 1,2,…,[f(i)−1]1, 2, \dots, [f(i)-1]1,2,…,[f(i)−1] 的最小值,设 f(i)−1f(i)-1f(i)−1 的周期为 sss,那么这个值只需要在 sss 的基础上使得它能够被 f(i)−1f(i)-1f(i)−1 整除,所以就是 f(i)−1f(i)-1f(i)−1 和 sss 的最小公倍数。
最后统计答案的时候,遍历每个 f(i)f(i)f(i) 的周期,由于我们是逐一考虑 f(i)f(i)f(i) 的,所以每次只要加上 ⌊ns⌋\left\lfloor\dfrac{n}{s}\right\rfloor⌊sn⌋ 即可。
Code
#include<bits/stdc++.h>
#define ll long long
#define inf (1<<30)
#define INF (1ll<<60)
using namespace std;
const ll MAXN=1e16;
const ll MOD=1e9+7;
ll top[110];
void solve(){
ll n;
scanf("%lld",&n);
ll ans=n*2%MOD;//加上奇数的值,并先把偶数的 3 加上 2
ans=(ans+n/2)%MOD;//先钦定所有偶数都是 3,由于上一行中已经加了 2,所以这里每个偶数只要 +1
for(int i=4;top[i]<=n;i++){
ans=(ans+n/top[i])%MOD;
//同理,我已经加了小 1 的值,所以这里每次只需要增加 1 就行
}
printf("%lld\n",ans);
}
ll gcd(ll x,ll y){return x%y==0?y:gcd(y,x%y);}
int main()
{
for(ll i=4,cur=2;cur<=MAXN;i++){
ll g=gcd(i-1,cur);
cur=cur*(i-1)/g;
top[i]=cur;
}//打表,top[i] 表示 f(x)=i 的周期
int T;
for(scanf("%d",&T);T--;)
solve();
return 0;
}
/*
*/