Description
对于任意的>1的n gcd(a, b)不是n^2的倍数
也就是说gcd(a, b)没有一个因子的次数>=2
Input
一个正整数T表示数据组数
接下来T行 每行两个正整数 表示N、M
Output
T行 每行一个整数 表示第i组数据的结果
Sample Input
4
2 4
3 3
6 5
8 3
Sample Output
24
28
233
178
HINT
HINT
T <= 10000
N, M<=4000000
Source
和这个差不多->【bzoj2154/2693】Crash的数字表格/jzptab 莫比乌斯反演
就是f的定义不同:
f(n)={1n0n是sfnotherwise
然后关于如何筛 F∗id∗id ,就变得很恶心了…
不过还是设 g=F∗id∗id ,推一下 g(pk) ,就很简单了…不过要稍微分类讨论一下…
打代码的时候要和推得式子统一!我草稿纸上写的g然后代码写的F,因此WA了好几次…
因为模的数是2的整数幂,相当于 ans and 230−1 ,爆int也无所谓。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int SZ = 5000010;
const int mod = (1 << 30) - 1;
int pri[SZ];
bool vis[SZ];
int g[SZ];
int sum[SZ];
void shai(int n)
{
g[1] = 1;
for(int i = 2,tot = 0;i <= n;i ++)
{
if(!vis[i]) pri[++ tot] = i,g[i] = i - i * i;
for(int j = 1,m;j <= tot && (m = i * pri[j]) <= n;j ++)
{
vis[m] = 1;
if(i % pri[j] == 0)
{
int x = i / pri[j];
if(x % pri[j] == 0) g[m] = 0;
else g[m] = -pri[j] * pri[j] * pri[j] * g[x];
break;
}
else
{
g[m] = g[i] * g[pri[j]];
}
}
}
for(int i = 1;i <= n;i ++)
sum[i] = sum[i - 1] + g[i];
}
int SUM(int n,int m)
{
int a = n * (n + 1) >> 1;
int b = m * (m + 1) >> 1;
return a * b;
}
int ask(int n,int m)
{
int ans = 0;
if(n > m) swap(n,m);
for(int i = 1,r;i <= n;i = r + 1)
{
r = min(n / (n / i),m / (m / i));
ans += (sum[r] - sum[i - 1]) * SUM(n / i,m / i);
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
shai(4000010);
while(T --)
{
int n,m;
scanf("%d%d",&n,&m);
printf("%d\n",ask(n,m) & mod);
}
return 0;
}