题目描述:
emmmm.
题目分析:
看一下不难发现 每个位置的损失值其实就是
gcd(i,j)∗2−1
g
c
d
(
i
,
j
)
∗
2
−
1
N2
N
2
暴力枚举就有80分了
转化一下即求
∑min(n,m)d=1[(2∗d−1)∗∑(gcd(i,j))=d]
∑
d
=
1
m
i
n
(
n
,
m
)
[
(
2
∗
d
−
1
)
∗
∑
(
g
c
d
(
i
,
j
)
)
=
d
]
求
gcd(i,j)=d
g
c
d
(
i
,
j
)
=
d
用莫比乌斯反演即可
总的复杂度即
O(n(√n))
O
(
n
(
n
)
)
卡一卡就过去了
正解好像是容斥,而且代码巨短~
题目链接:
Ac 代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#define int long long
const int maxm=110000;
int mu[maxm],prime[maxm],sum[maxm],cnt,n,m;
bool vis[maxm];
void getmu()
{
mu[1]=1,vis[1]=1;
for(int i=2;i<=maxm;i++)
{
if(!vis[i])
{
prime[++cnt]=i;
//printf("%d\n",i);
mu[i]=-1;
}
for(int j=1;j<=cnt&&prime[j]*i<=maxm;j++)
{
vis[prime[j]*i]=1;
if(i%prime[j]==0)
{
mu[prime[j]*i]=0;
break;
}
mu[prime[j]*i]=-mu[i];
}
}
for(int i=1;i<=maxm;i++) sum[i]=mu[i]+sum[i-1];
}
int gcd(int x,int y)
{
int ans=0,last;
for(int i=1;i<=std::min(x,y);i=last+1)
{
last=std::min(x/(x/i),y/(y/i));
ans+=(sum[last]-sum[i-1])*(x/i)*(y/i);
}
return ans;
}
int cal(int a,int b,int c,int d,int k)
{
a--,c--;
a/=k,b/=k,c/=k,d/=k;
return gcd(b,d)-gcd(b,c)-gcd(a,d)+gcd(a,c);
}
main()
{
getmu();
//printf("Yes\n");
scanf("%lld%lld",&n,&m);
int ans=0;
for(int i=1;i<=std::min(n,m);i++)
ans+=(cal(1,n,1,m,i)*(2*i-1));
printf("%lld\n",ans);
return 0;
}