您的位置:首页 > 其它

【bzoj2694】Lcm 莫比乌斯反演

2016-01-25 21:35 337 查看

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: