2820: YY的GCD
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 1461 Solved: 762
[ Submit][ Status][ Discuss]
Description
神犇YY虐完数论后给傻×kAc出了一题给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对kAc这种
傻×必然不会了,于是向你来请教……多组输入
Input
第一行一个整数T 表述数据组数接下来T行,每行两个正整数,表示N, M
Output
T行,每行一个整数表示第i组数据的结果
Sample Input
2
10 10
100 100
10 10
100 100
Sample Output
30
2791
2791
HINT
T = 10000
N, M <= 10000000
Source
莫比乌斯反演
还是一样,,(每组询问默认n<=m)
f[i]:最大公约数为i的个数
F[i]:以i为约数的个数
F[i] = [n/i]*[m/i]
f[i] = ∑u(d/i)*F[i] (d是i的倍数)
不过本题,,需要求gcd(i,j)为质数的个数,,
上述只能在根号n的时间内求出单个f[i]
列出一般解法的式子
ans = ∑∑u(d/p)[n/d]*[m/d] (p是质数,d是p的倍数)
换种思路,不直接枚举d,而是枚举一个i,使得
ans = ∑∑u(i)*[n/(pi)]*[m/(pi)]
令T = pi,换元
ans = ∑∑u(T/p)*[n/T]*[m/T]
调一下∑的顺序
ans = ∑[n/T]*[m/T]*∑u[T/p]
根据原始的式子,T必须是p的倍数,且p是个素数
[n/T]*[m/T] 这玩意的取值显然是只有2(根号n+根号m)
枚举之
如果我们能O(1)得出∑u[T/p]
那么算法的复杂度就是O(Q根号n) (Q为询问个数)
按照之前的前缀和思路
对于∑u[T/p],只有T%p == 0的情况莫比乌斯函数对于T才有效
筛法后处理下就好O(nlogn)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
const int maxn = 1E7 + 10;
typedef long long LL;
LL mu[maxn],sum[maxn];
int n,m,T;
bool not_prime[maxn];
LL Mu(LL n,LL m)
{
LL ret = 0;
int last,tail = min(n,m);
for (LL i = 1; i <= tail; i = last + 1) {
last = min(n/(n/i),m/(m/i));
ret += (n/i)*(m/i)*(sum[last] - sum[i-1]);
}
return ret;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
for (int i = 1; i < maxn; i++) mu[i] = 1;
for (int i = 2; i < maxn; i++)
if (!not_prime[i]) {
mu[i] = -1;
for (int j = 2; ; j++) {
int x = i*j;
if (x >= maxn) break;
not_prime[x] = 1;
mu[x] *= mu[i];
if (j % i == 0) mu[x] = 0;
}
}
for (int i = 2; i < maxn; i++)
if (!not_prime[i])
for (int j = 1; ; j++) {
int x = i*j;
if (x >= maxn) break;
sum[x] += mu[j];
}
for (int i = 1; i < maxn; i++) sum[i] += sum[i-1];
cin >> T;
while (T--) {
scanf("%d%d\n",&n,&m);
printf("%lld\n",Mu(n,m));
}
return 0;
}