Zeldain Garden(求1-n中因子个数的和)详解

https://ac.nowcoder.com/acm/contest/7817/E


这道题之前,有一个原题---因数个数和

主要讲两种解释方法。

首先转化一下思维,考虑每个数的贡献。什么意思呢?

比如1-n中考虑1这个数能作为多少数的因子,那么就是说1-n中有多少个数是1的倍数,那么是n/1个。

2这个数能作为多少数的因子,那么就是说1-n中有多少个数是2的倍数,那么是n/2个。

所以,这样下来得出式子n/1+n/2+n/3+n/4+.....n/n;

转化可得,n*(1/1+1/2+1/3+1/4+1/5+....1/n);

把这个看成y=n/x的函数,其中x只能取正整数。那么怎么求这个函数的离散和呢?

观察到这个函数是关于y=x对称的,且这个对称点在x=n/x----->x=sqrt(n);

那么这样我们只要求一半就好。怎么求呢?

把n看成是一个矩形的长,1/x看成这个矩形的高,那么一个离散值n/x就是这个矩形的面积,那么曲线的一半就可以sqrt(n)内枚举每一个n对应的矩形面积是多少,然后求和,之后乘2。注意这么算最后有一段矩形的面积是重合的,重复的面积是那个正方形的长度和高度为sqrt(n)的矩形。


这里的内容参考:https://blog.csdn.net/u011787439/article/details/82183783?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-9.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-9.channel_param

方法1:最简单的就是把1~x各个数的因数个数都求出来再求和。

不过这样做显然会超时。

方法2:换一种思路考虑,从1~x 这x个数,每个数都会有1这个因数,每2个数会有一个因数2,每3个数会有一个因数3,.......

所以,1~x 共有 x/1 个因数1,x/2个因数2,x/3个因数3,……,x/n个因数n(1<=n<=x),所以最终个数和为\sum_{i=1}^{x}{x/i}

再写代码就比较简单了,这里就不赘述了。但还能不能把计算时间再缩小下呢,或者说有没有计算量更小的方法呢?

方法3:假设n为x的因数,那么x/n 也一定为x的因数,假设sq为x的算术平方根,那么x的因数可以分为两部分,一部分都小于sq,一部分都大于(等于)sq。基于方法2,我们也就只需要计算\sum_{i=1}^{sq}{x/i}的数值,然后再乘以2。于是我们兴致勃勃的去写代码了,但是发现程序跑出来的结果并不正确。比之前多了许多。

这里的方法三就涉及到去重的问题,每一个数在sqrt(n)的时候重复了一个,这样的平方数在n以内一共有sqrt(n)个。所以是sqrt(n)*sqrt(n);想看具体例子的可以点那个链接去原博主的博客看。 


#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e3+100;
typedef long long LL;
LL n;
void solve()
{
    LL ans=0;
    LL t=sqrt(n);
    for(LL i=1;i<=t;i++) ans+=(n/i);
    cout<<ans*2-t*t<<endl;
}
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL t;cin>>t;
  while(t--)
  {
  	cin>>n;
  	solve();
  }
return 0;
}

那么对于这题而言,就是考虑一个前缀和的情况。拿1-m的减去1-n的。不过要注意n==1的时候要特判。

#include<iostream>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
ull factor_count(ull n)
{
	ull res=n;
	ull i;
	for(i=2;i*i<=n;++i){
		res += 2 * (n/i);
	}
	i--;
	return res+(n-i*i);
}


int main()
{
	ull n,m;
    cin>>n>>m;
    if(n==1){
        cout<<factor_count(m)<<endl;
    }
    else cout<<factor_count(m)-factor_count(n-1)<<endl;
	return 0;
}
///1 3
///1 1
///1 4

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/108904566
今日推荐