目标是求
的和:
做法是将相同
的连续一个区间看做一个块,例如区间
中所有的
的
的值都相同,那么我直接
所以依次枚举区间的左边界,然后找到最大的右边界
,然后累加
,最后将
设置为
,继续找下一个块
下面是基本代码:
int ans = 0;
for(int i = 1; i <= n; i ++){
int l = i, r = 😀
ans = ans + (r - l + 1) * (n / i);
i = r;
}
cout << ans << endl;
有两个问题:-
最大可以为
,这样枚举一个个块,虽然比直接的暴力循环优化了许多,但是能保证仍然不会超时吗?
-
最关键的,如果求出有边界
回答问题1:
显然时间复杂度直接与枚举的块的数量直接挂钩,如果块有
,那依旧超时。但是,块的数量不会超过
个
证明:
将区间
拆分为两个区间
和
区间
只有
个数,那么块的数量肯定就是小于等于
区间
的数可能很多,例如当
时,
,那么有
个数,但是
,
,它的商值的个数不会超过
个,也就是说块的数量也不会超过
个个
所以区间
的块的数量不会超过
个
回答问题2:
如何求有边界
?给出结论
,那么下面需要证明两个等式:
证明过程:
先证明
:
因为
,因为
为整数,那么
,所以
得到
,即
在证明
:
因为
,两边同时取倒数,得到
, 两边同时乘以
,得到
然后
两边在同时取整数,得到
,因为
已经时整数了,所以直接是
,即
那么
得到证明
那为什么要证明等式2?因为这个有区间边界
肯定要最大,要不然这个块就没有取完整,例如
是一个块,但是取的
为
,那肯定就不对
首先令
,即证明
,其中
所以
,因为
是一个整数,那么
所以
得到证明
总代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;
signed main(){
HelloWorld;
int n; cin >> n;
int ans = 0;
for(int i = 1; i <= n; i ++){
int l = i, r = (n / (n / i));
ans = ans + (r - l + 1) * (n / i);
i = r;
}
cout << ans << endl;
return 0;
}



京公网安备 11010502036488号