您的位置:首页 > 其它

bzoj2005 能量采集 gcd 容斥

2016-06-03 17:13 316 查看
ans = sigma_x(sigma_y(gcd(x,y) * 2 - 1)),1<=x<=n,1<=y<=m

枚举x,y,O(nmlogn),超时

换个角度,枚举d = gcd(x,y)

d对ans的贡献为2*d-1

若有n个(x,y)使得gcd(x,y) = d,则贡献为n * (2 * d - 1)

f(d) 表示gcd(x,y) = d 的(x,y)个数

ans = sigma(f[d] * (2 * d - 1)),1 <= d <= min(n,m)

那么问题就是求f(d)


g(d) 表示d|gcd(x,y)的(x,y)个数

则g(d) = (n / d) * (m / d)

f(d) = g(d) - f(i * d) , 2 <= i <= min(n,m) / d

反序遍历d,即min(n,m) 到 1


求f(d),累加f(d) * (2 * d - 1) 到ans

O(nlogn)

//File Name: bzoj2005.cpp
//Author: long
//Mail: 736726758@qq.com
//Created Time: 2016年02月12日 星期五 14时08分18秒

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>

#define LL long long

using namespace std;

const int MAXN = 100000+5;

LL f[MAXN];

void solve(int n,int m)
{
LL ans = 0LL;
int mi = min(n,m);
memset(f,0,sizeof f);
for(int i=mi;i>0;i--){
f[i] = (LL)(n/i) * (m/i);
for(int j=2;j<=mi/i;j++){
f[i] -= f[j*i];
}
ans += f[i] * (i * 2LL - 1);
}

cout << ans << endl;
return ;
}

int main()
{
int n,m;
while(~scanf("%d %d",&n,&m)){
solve(n,m);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: