题目链接: https://ac.nowcoder.com/acm/contest/549/J
题意:
思路:
接着1的倍数的 n*m
2的倍数的 n/2*m/2
3的倍数的 n/3*m/3
…
所以d的倍数的,得减去 2d,3d,4*d,…的结果,最后剩下的就是gcd(i,j)==d的结果了
#include
#define mod 1000000007
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
bool check[maxn];
int prime[maxn];
int mu[maxn];
void get_mo()
{
mu[1]=1;
int cnt=0;
for(int i=2;i<maxn;i++)
{
if(!check[i])
{
prime[cnt++]=i;
mu[i]=-1;
}
for(int j=0;j<cnt;j++)
{
if(i*prime[j]>maxn)
break;
check[i*prime[j]]=true;
if(i%prime[j]==0){
mu[i*prime[j]]=0;
break;
}
else
{
mu[i*prime[j]]=-mu[i];
}
}
}
}
int main()
{
int n,m;
cin>>n>>m;
get_mo();
if(n>m)
swap(n,m);
ll ans=0;
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j+=i)
{
ans=(ans+(1ll*i*i%mod)*mu[j/i]*(n/j)*(m/j))%mod;
}
}
cout<<ans<<endl;
return 0;
}
利用容斥也可做
#include
using namespace std;
typedef long long LL;
const int N=1e6+10;
const int mod=1000000007;
LL f[N];
int main(){
LL n,m;
scanf("%lld %lld",&n,&m);
LL res=0;
for(int i=min(n,m);i>=1;i--){
f[i]=(n/i)*(m/i);//这里的括号必须有,要不然,会出错
for(int j=i*2;j<=min(n,m);j+=i)
f[i]-=f[j];
res=(res+f[i]*i%mod*i%mod)%mod;
}
printf("%lld\n",res);
return 0;
}