每个数i的函数F(i)定义为其所有因子之和
给定a,b<=1e12,相差不超过1e6,求a到b的所有F(i)之和
https://blog.csdn.net/computer_user/article/details/79957509
显然是要枚举因子算贡献,
然后要搞前缀和算[1,r]-[1,l-1]
两种做法,
一个是这次要学的援引的博主的做法……
另一个是自己瞎搞搞出来的,先枚举数出现的次数,再枚举数的值,两个1e6能摊出来
可以看出,一段区间的出现次数都是相同的,那我们不妨枚举区间
这个区间的段数不会超过1e6
比如对于n=10,可分成这些段[1][2][3][4,5][6,10]
分别出现10次,5次,3次,2次,1次
那么,对于当前端点l,l出现了n/l次,
而同样出现n/l次的数,最大为r=n/(n/l),
这个向下取整的操作真的惊艳啊
那么对于[l,r]这段区间的数都出现了n/l次,
其贡献为(l+r)*(r-l+1)/2*(n/l),
然后令l=r+1,去统计下一段区间的贡献即可
大概是区间筛???
筛法这里真的感觉好高深啊QAQ
爆了ll 但不会爆ull,这个坑点又wa了若干发
回头总结一下__int128的板子只要内存大就开__int128
天天爆ll还玩个锤子
#include
#include
#include
#include
#include
using namespace std;
typedef unsigned long long ull;
ull n,m;
ull func(ull n)
{
ull ans=0,r;
for(ull l=1;l<=n;l=r+1)//枚举区间段 妙啊
{
r=n/(n/l);
ans+=(l+r)*(r-l+1)/2*(n/l);//[l,r]内均出现n/l次
}
return ans;
}
int main()
{
while(~scanf("%llu%llu",&n,&m))
printf("%llu\n",func(m)-func(n-1));
return 0;
}
#include
#include
#include
#include
#include
using namespace std;
typedef unsigned long long ull;
ull func(ull n,ull m)
{
ull ans=0;
for(ull i=1;i<=1e6;++i)//枚举出现i次的数在[l,r]内,不超过1e6
{
ull l=(n+i-1)/i,r=m/i;//l为n除以i向上取整
if(r