您的位置:首页 > 其它

[NOI2010] 能量采集

2018-03-26 08:56 218 查看

题目描述:

emmmm.

题目分析:

看一下不难发现 每个位置的损失值其实就是 gcd(i,j)∗2−1gcd(i,j)∗2−1

N2N2暴力枚举就有80分了

转化一下即求

∑min(n,m)d=1[(2∗d−1)∗∑(gcd(i,j))=d]∑d=1min(n,m)[(2∗d−1)∗∑(gcd(i,j))=d]

求gcd(i,j)=dgcd(i,j)=d用莫比乌斯反演即可

总的复杂度即O(n(√n))O(n(n))

卡一卡就过去了

正解好像是容斥,而且代码巨短~

题目链接:

BZOJ 2005

Luogu 1447

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