题目地址:https://www.luogu.org/problemnew/show/P2257
参考了大佬的思路:https://www.luogu.org/blog/peng-ym/solution-p2257
可以结合我的hdu1695题解看一下,这道题是1695的加强版 ,原文地址:https://blog.csdn.net/xiaoshazheng/article/details/85712803
本题算法是莫比乌斯反演,感觉推的过程有点多,我就直接上手写版了
过程感觉写的比较详细,有什么没写清楚的可以在评论里问我。
附代码:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define maxn 10000100
using namespace std;
int prime[maxn],cnt,mo[maxn],x[maxn];
long long sum[maxn];
bool f[maxn];
void data()
{
cnt=0;
memset(f,true,sizeof(f));
memset(x,0,sizeof(x));
sum[0]=0;
f[0]=f[1]=false;
mo[1]=1;
for(int i=2;i<=maxn;i++)
{
if(f[i])
{
prime[cnt++]=i;
mo[i]=-1;
}
for(int j=0;j<cnt&&i*prime[j]<=maxn;j++)
{
f[i*prime[j]]=false;
if(i%prime[j])
mo[i*prime[j]]=-1*mo[i];
else
{
mo[i*prime[j]]=0;
break;
}
}
}
//printf("%d\n",prime[0]);
for(int j=0;j<cnt;j++)
for(int i=1;i*prime[j]<=maxn;i++)
{
x[i*prime[j]]+=mo[i];
}
for(int i=1;i<=maxn;i++)
{
sum[i]+=sum[i-1]+x[i];
}
}
int main()
{
data();
int t,minn,n,m;
long long ans;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
minn=min(n,m);
ans=0;
for(int l=1,r;l<=minn;l=r+1)
{
r=min(n/(n/l),m/(m/l));
ans+=(long long)(n/l)*(m/l)*(sum[r]-sum[l-1]);
}
printf("%lld\n",ans);
}
return 0;
}
发现了一个可怕的点,第62行必须要加(long long)转化,不加就只能50分,而且把(long long)换成111*也能过,而且还是数字1.笑哭笑哭笑哭笑哭笑哭笑哭笑哭笑哭笑哭笑哭笑哭笑哭笑哭笑哭