给n,求n/1+n/2+n/3+....+n/n的值

给n,求n/1+n/2+n/3+…+n/n的值

首先,n最大范围1e9,暴力肯定超时
那么先看一段代码
#include<bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define re register int
typedef long long ll ;
using namespace std;
const int N =  1e6 + 10 , M = 1010 , inf = 0x3f3f3f3f , mod = 1e9 + 7 ;

int main()
{
    int n ;
    cin >> n ;
    for(int l = 1 , r ; l <= n ; l = r + 1)
    {
        r = n / (n / l) ;
        printf("%d %d %d\n",n/l,l,r) ;
    }
    return 0;
}
我们输入100  可以得到的结果是
n / l  l  r
100  1  1
50  2  2
33  3  3
25  4  4
20  5  5
16  6  6
14  7  7
12  8  8
11  9  9
10  10  10
9  11  11
8  12  12
7  13  14
6  15  16
5  17  20
4  21  25
3  26  33
2  34  50
1  51  100
那么,很明显从51到100中的数,除n都等于1
从34到50中的数,除n都等于2
以此类推从l到r中的数,除n都等于n/l
那么每次给出左端点,如何求右端点
考虑一下假设左端点为l
那么 n / (n / l ) 是不是就是右端点
因为c++默认下取整
在算出当前区间的左右端点的情况下
下一个区间的左端点就是上一个区间的右端点+1
那么答案就是(r - l + 1) * (n / l )

时间复杂度分析

#include<bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define re register int
typedef long long ll ;
using namespace std;
const int N =  1e6 + 10 , M = 1010 , inf = 0x3f3f3f3f , mod = 1e9 + 7 ;

int main()
{
    int n ;
    cin >> n ;
    int cnt = 0 ;
    for(int l = 1 , r ; l <= n ; l = r + 1)
    {
        r = n / (n / l) ;
        cnt ++ ;
    }
    cout << cnt << endl;
    return 0;
}
我们分别输入100 10000 1000000 100000000
可以得到结果是 19 199 1999 19999
因此时间复杂度为 2sqrt(n)

最后ac代码

#include<bits/stdc++.h>
#define fer(i,a,b) for(re i = a ; i <= b ; ++ i)
#define re register int
typedef long long ll ;
using namespace std;
const int N =  1e6 + 10 , M = 1010 , inf = 0x3f3f3f3f , mod = 1e9 + 7 ;

int main()
{
    int t ;
    cin >> t ;
    while(t--)
    {
	    int n ;
	    cin >> n ;
	    ll res = 0 ;
	    for(int l = 1 , r ; l <= n ; l = r + 1)
	    {
	        r = n / (n / l) ;
	        res += (r - l + 1 ) * (n / l );
	    }
	    //一维数论分块
	    cout << res << endl;
    }
    return 0;
}

二维数论分块

int solve(int n, int m)
{
	    int res = 0;
	    for(int i = 1, j; i <= min(n, m); i = j + 1){
	        j = min(n / (n / i), m / ( m / i));//j是右边界,这里的值都是i
	        res += (j - i + 1) * (n / i) * (m / i);
	    }
	    return res;
}
  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值