**题目来源: Project Euler
基准时间限制:6 秒 空间限制:131072 KB 分值: 640 难度:8级算法题**
定义F(n)表示最小公倍数为n的二元组的数量。
即:如果存在两个数(二元组)X,Y(X <= Y),它们的最小公倍数为N,则F(n)的计数加1。
例如:F(6) = 5,因为[2,3] [1,6] [2,6] [3,6] [6,6]的最小公倍数等于6。
给出一个区间[a,b],求最小公倍数在这个区间的不同二元组的数量。
例如:a = 4,b = 6。符合条件的二元组包括:
[1,4] [2,4] [4,4] [1,5] [5,5] [2,3] [1,6] [2,6] [3,6] [6,6],共10组不同的组合。
Input
输入数据包括2个数:a, b,中间用空格分隔(1 <= a <= b <= 10^11)。
Output
输出最小公倍数在这个区间的不同二元组的数量。
Input示例
4 6
Output示例
10
可以推导,先考虑大小没有限制的二元组情况:
但是这种是对于二元组没有大小关系限制时的答案。
设有 即因子个数函数。
现在:
我们来考虑一下
那么;
然后分块处理:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<cmath>
#define maxx 5000000
#define mod 1000000007
#define ll long long
using namespace std;
map<ll,ll>g;
ll G(ll n)
{
if(g[n])return g[n];
ll ans=(ll)sqrt(n);
//while((ans+1)*(ans+1)<=n)ans++;
for(ll i=1,last;i<=n;i=last+1)
{
last=n/(n/i);
ans+=(last-i+1)*(n/i);
}
ans/=2;
g[n]=ans;
return ans;
}
map<ll,ll>f;
ll F(ll n)
{
if(f[n])return f[n];
ll ans=0;
for(ll i=1,last;i<=n;i=last+1)
{
last=n/(n/i);
ans+=(G(last)-G(i-1))*(n/i);
}
f[n]=ans;
return ans;
}
int main()
{
cout<<F(6)<<endl;
ll a,b;
cin>>a>>b;
cout<<F(b)-F(a-1)<<endl;
return 0;
}
但是这种推导下来,发现和实际值有出入,但是实在不知道哪里有问题,希望哪位大佬可以指出问题。
换另一种推法:
枚举gcd:
这里可以引入欧拉函数或者莫比乌斯函数,但是欧拉函数似乎没什么用啊。
用莫比乌斯搞一下: