2021-07-05

C. Strange Function

Let f(i) denote the minimum positive integer x such that x is not a divisor of i.

Compute ∑ i = 1 n f ( i ) \sum_{i=1}^{n} f(i) i=1nf(i) modulo 1 0 9 10^9 109+7. In other words, compute f(1)+f(2)+⋯+f(n) modulo 1 0 9 10^9 109+7.

Input
The first line contains a single integer t (1≤t≤ 1 0 4 10^4 104), the number of test cases. Then t cases follow.

The only line of each test case contains a single integer n (1≤n≤ 1 0 16 10^{16} 1016).

Output
For each test case, output a single integer ans, where ans= ∑ i = 1 n f ( i ) \sum_{i = 1}^{n}f(i) i=1nf(i) modulo 1 0 9 10^9 109+7.

C.奇怪的功能

让 f(i) 表示最小正整数 x,使得 x 不是 i 的除数。

计算 ∑ i = 1 n f ( i ) \sum_{i=1}^{n} f(i) i=1nf(i) 1 0 9 10^9 109 + 7。 换句话说,计算 f(1)+f(2)+⋯+f(n) 模 1 0 9 10^9 109 + 7。

输入
第一行包含一个整数 t (1≤t≤ 1 0 4 10 ^4 104),即测试用例的数量。 然后是 t 个案例。

每个测试用例的唯一一行包含一个整数 n (1≤n≤ 1 0 16 10^{16} 1016)。

输出
对于每个测试用例,输出单个整数 ans,其中 ans= ∑ i = 1 n f ( i ) \sum_{i = 1}^{n}f(i) i=1nf(i) modulo 1 0 9 10^9 109+7。

思想:
如果真的要从f(1)加到f(n)的话,绝对直接爆炸,所以我们需要寻找其他的方法。由于一个数n所有的除数的最小公倍数是小于等于n的,我们可以想到,题目定义f(x)是x的最小正整数,并且这个正整数不是x的除数,那么我们就枚举所有f(x) = 2的x有多少个,结果加上2 * (x的个数),所有f(x) = 3的x有多少个,结果加上3 * (x的个数)…最终我们就求得结果。值得注意的是,我们需要发现f(x)=m,m枚举到多少?想一下,当m越来越大的时候,1,2,3,4,5,…m - 1的公倍数也就很大很大了。所以其实m不是很大。
而求f(x) = 2的情况下,那些不是2的倍数的元素的f(x)就是等于2的(因为不是2的倍数的元素就不包含2这个除数)对于f(x) = 3,4,5,…同理。我们先求得2的倍数的个数,然后用n 减去 2的倍数的个数,这就是f(x) = 2的元素个数。对于f(x) = 3, 4, 5, …同理。
在1到n中,2的倍数的元素个数有n / 2个,3的倍数的元素个数有n / 3个,但是需要注意的是,有些元素会是2 和 3 的倍数,比如 6,12 等,所以假如我们需要求是3的倍数的元素个数,我们必须先把是2的倍数的元素给去除,同理,求是4的倍数的元素个数的时候要去掉是2,和3的元素。可以用最小公倍数得到,比如求4的倍数的元素个数就是n / lcm(2, 3, 4)(lcm函数是求最小公倍数的)。
求f(x) = i就是让当前集合中的个数减去是i的倍数的元素个数,先举个例子:
假如n = 14,即求f(1) + f(2) + … + f(14);
1.先将1到n的元素全列入集合,此时集合为:{1,2,3,4,5,6,7,8,9,10,11,12,13,14};
2.求出f(x) = 2的x的元素个数:因为是2的倍数的元素个数为14 / 2 = 7个,那么就有14 - 7 = 7个不是2的倍数的元素,此时f(x) = 2的x的元素个数有7个,那么ans += 2 * 7,因为不是2的倍数的元素个数已经被算入f(x) = 2中了,所以集合变为{2,4,6,8,10,12,14}
3.求出f(x) = 3的x的元素个数:因为是3的倍数而不是2的倍数的元素个数为14 / lcm(2, 3) = 14 / 6 = 2个,所以不是2的倍数也不是3的倍数的元素个数为7 - 2 = 5个,所以集合变为{2,4,8,10,14}

代码如下:

#include<iostream>
 
using namespace std;
 
const int p = 1e9 + 7;
 
long long gcd(long long a, long long b){
    return b ? gcd(b, a % b) : a;
}
 
long long lcm(long long a, long long b)
{
    return a / gcd(a, b) * b;
}
 
int main()
{
    int t;
    cin >> t;
    while(t --){
        long long n;
        cin >> n;
        
        int x = 2;
        long long ans = 0, res = 1;
        long long geshu = n;
        while(res <= n){
            res = lcm(res, x);
            if(geshu <= 0)  break;
            ans += x * (geshu - n / res);
            geshu = n / res;
            x ++;
        }
        cout << ans % p << endl;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值