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),所以最终个数和为
再写代码就比较简单了,这里就不赘述了。但还能不能把计算时间再缩小下呢,或者说有没有计算量更小的方法呢?
方法3:假设n为x的因数,那么x/n 也一定为x的因数,假设sq为x的算术平方根,那么x的因数可以分为两部分,一部分都小于sq,一部分都大于(等于)sq。基于方法2,我们也就只需要计算的数值,然后再乘以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