Gym-101652P Fear Factoring(枚举贡献/数论分块)

题目

每个数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还玩个锤子

代码1

#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;
} 

代码2

#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

 

你可能感兴趣的:(数论)