输入文件包含多组测试数据。
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