

输入文件包含多组测试数据。
T行,每行一个整数,表示你所求的答案。
1<=N, M<=50000
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3994
题目分析:和上一题类似,还是见公式:
于是得到:
变形得到
继续变形
现在的问题是怎样计算f的值,f[i]表示的是
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
int const MAX = 50005;
//mob表示莫比乌斯函数,sum表示莫比乌斯函数前缀和,p表示素数
int mob[MAX], sum[MAX], p[MAX];
//facnum表示约数个数,f表示约数个数前缀和,d表示最小质因子的次幂
int facnum[MAX], f[MAX], d[MAX];
//prime是用来筛素数
bool noprime[MAX]; //前缀和数组其实可以直接由一个数组得到,这样申明只是为了让意思更清楚
void Mobius()
{
int pnum = 0;
mob[1] = 1;
sum[1] = 1;
f[1] = 1;
facnum[1] = 1;
for(int i = 2; i < MAX; i++)
{
if(!noprime[i])
{
p[pnum ++] = i;
mob[i] = -1;
facnum[i] = 2; //素数的因子只有本身和1
d[i] = 1; //素数的最小质因子的次幂显然为1
}
for(int j = 0; j < pnum && i * p[j] < MAX; j++)
{
noprime[i * p[j]] = true;
if(i % p[j] == 0)
{
mob[i * p[j]] = 0;
//这里当前最小质因子的次幂加了1,因为i是p[j]的倍数,又乘了p[j]
facnum[i * p[j]] = facnum[i] / (d[i] + 1) * (d[i] + 2);
d[i * p[j]] = d[i] + 1;
break;
}
mob[i * p[j]] = -mob[i];
//facnum[i * p[j]] = facnum[i] * facnum[p[j]]
//积性函数的性质i和p[j]显然互质,又facnum[p[j]] = 2,素数只有两个因子
facnum[i * p[j]] = facnum[i] * 2;
//此时当前最小质因子的次数为1
d[i * p[j]] = 1;
}
sum[i] = sum[i - 1] + mob[i];
f[i] = f[i - 1] + facnum[i];
}
}
ll cal(int l, int r)
{
ll ans = 0;
if(l > r)
swap(l, r);
for(int i = 1, last = 0; i <= l; i = last + 1)
{
last = min(l / (l / i), r / (r / i));
ans += (ll) f[l / i] * f[r / i] * (sum[last] - sum[i - 1]);
}
return ans;
}
int main()
{
Mobius();
int T;
scanf("%d", &T);
while(T--)
{
int n, m;
scanf("%d %d", &n, &m);
printf("%lld\n", cal(n, m));
}
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
BZOJ 3994 [SDOI2015]约数个数和 (神定理+莫比乌斯反演)
原文地址:http://blog.csdn.net/tc_to_top/article/details/48024261