题意
定义 f(i) 为 x ,x 为 非i的因子的最小正整数。
给一个n。求 f(1) + f(2) + … + f(n) % 1e9+7
思路
f(i) = x,等价于 i 整除 lcm(1, … , x-1), i 不 整除 lcm(1, … , x)。
可以用贡献度思想 / 集合的思想。
首先我们这么定义:
设 a = lcm(1, … , i),
则 b = lcm(1,…, i+1)
则 c = lcm(1,…, i+2) = lcm(b , i+2) .
在1…n 里 整除a 的数的个数为 n / a 。
在1…n 里 整除b 的数的个数为 n / b 。
在1…n 里 整除c 的数的个数为 n / c。
我们定义一个 下标为 1 … n 的数组 F [ ], F [ i ] = f(i)
数组F 初始全为0。
假设i == 1
则,a = 1 ,b = 2,c = 6 .
即 a = lcm(1,1)
b = lcm(1,2)
c = lcm(1,2,3)
让所有整除a的数 + 1
F | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
– | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
让所有整数b的数 + 1
F | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
– | 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 | 1 | 2 |
让所有整除c的数 + 1
F | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
– | 1 | 2 | 1 | 2 | 1 | 3 | 1 | 2 | 1 | 2 | 1 | 3 |
这时我们惊奇的发现,
对于x == 2 和 x == 3 ,都满足:
当f(i) = x时, F[i] = x-1
这时如果让整除lcm(1, … 4) 的下标都+1
F | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
– | 1 | 2 | 1 | 2 | 1 | 3 | 1 | 2 | 1 | 2 | 1 | 4 |
则 对于x == 3,也满足 当f(i) = x时, F[i] = x-1
这是因为,当从i == 1开始 一直 对 整除 lcm (1, … , i+1) 的下标 + 1 。
那么当 i > 2 时,所有的整除lcm(1, … , i ) 的数,都被加了 i - 1 下。
(因为从i = 1 开始,这些数都一直被加1,直到 对整除了lcm(1, … ,i+1)的下标+1 后,这些数都不会增加了)。
证明:
证明依据,当 x 整除 lcm(1, … i) 时,x一定整除 lcm(1,…,i-1) 。
所以我们可以从i == 1 开始,对 n 以内 整除 lcm(1,…,i) 的数+1.
也就是 a = lcm(1,…,i) , ans += n/a 。(n以内整除 a的数有 n/a 个)
一直到lcm(1,…,i) > n 为止,这样 F 数组的所有元素都满足 F[i] = f(i) - 1.
最后只需要 加上n就行。
Ac代码:
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
ll gcd(ll a,ll b){
if(b == 0) return a;
return gcd(b,a%b);
}
ll lcm(ll a,ll b){
// cout<<a<<" "<<b<<" "<<a*b / gcd(a,b)<<endl;
return a*b / gcd(a,b);
}
int main()
{
int t;
cin>>t;
while(t--){
ll n;
cin>>n;
ll x = 1;
ll i = 2;
ll ans = n % mod;
while(x <= n){
ll nums = n/x;
ans = (ans + nums ) % mod;
// cout<<"now asn = "<<ans<<endl;
x = lcm(i,x);
i++;
}
cout<<ans<<endl;
}
return 0;
}