# BZOJ 2005 [Noi2010]能量采集

F(k)=f(k)+f(2k)+..
f(k)=sigma u(i)F(ik)
ans=sigma[(2k-1)*f(gcd(x,y)=k)]
=sigma[(2k-1)*  sigma[u(i)*F(gcd(x,y)=ki)]  ]

sigma[u(i)*F(gcd(x,y)=ki)]=u(i)*(n/ki)*(m/ki);

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=100000;
int mu[maxn+5],book[maxn+5],prime[maxn+5],a[maxn+5];
int tot;
void mo()
{
mu[1]=1;
memset(book,false,sizeof(book));
tot=0;
a[1]=1;
for(int i=2;i<=maxn;i++)
{
if(!book[i])	prime[tot++]=i,mu[i]=-1;
for(int j=0;j<tot&&i*prime[j]<=maxn;j++)
{
book[i*prime[j]]=true;
if(i%prime[j]==0) break;
else		      mu[i*prime[j]]=-mu[i];
}
a[i]=a[i-1]+mu[i];
}

}
long long clac(int n,int m)
{
long long ans = 0;
int Min=min(m,n);
for (int i = 1, la = 0; i <= Min; i = la + 1)
{
la = min(n / (n / i), m / (m / i));
ans += (long long)(a[la] - a[i - 1]) * (n/i) *(m/i);      //区间[i，la]为一块
}
return ans;
}
int main()
{
int m,n;
mo();
long long ans=0;
while(~scanf("%d%d",&n,&m))
{
ans=0;
if(n>m) swap(n,m);
for(int i=1;i<=n;i++)
ans+= 2LL*i*clac(n/i,m/i);
printf("%lld\n",ans-1LL*n*m);

}
return 0;
}

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客