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<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
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<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
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<l)continue;//举不出break不行的反例 continue肯定是对的 
		if((l+r)%2==0)ans+=(l+r)/2*(r-l+1);
		else ans+=(r-l+1)/2*(l+r);//[l,l+i,…,r-i,r]均为i的倍数 
	}
	for(ull i=1;i<=1e6;++i)//枚举因子i,统计其出现次数,至少要大于1e6 
	{
		if(m/i<1e6)break;
		ull num=max((ull)1e6,(n-1)/i);//出现num次的数i 
		ans+=(m/i-num)*i;
	}
	return ans; 
}
int main()
{ 
   ull n,m; 
   while(~scanf("%llu%llu",&n,&m))
   printf("%llu\n",func(n,m));
   return 0;
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值