[2019.1.14]BZOJ2005 [Noi2010]能量采集

博客围绕点到原点路径上的能量损耗展开,给出点\((x,y)\)到\((0,0)\)路径能量损耗公式为\(2\times gcd(x,y)-1\),探讨如何统计\(\sum_{i=1}^n\sum_{j=1}^m 2\times gcd(i,j)-1\),介绍了相关函数定义及计算方法,最终得出时间复杂度为\(O(nlogn)\)。

以下设\(n\ge m\)

首先,一个点\((x,y)\)\((0,0)\)的路径上经过的点的数量(不包括首尾)为\(gcd(x,y)-1\)

所以它的能量损耗为\(2\times gcd(x,y)-1\)

考虑如何统计\(\sum_{i=1}^n\sum_{j=1}^m 2\times gcd(i,j)-1\)

\(f_x=\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=x]\),即\(1\le i\le n,1\le j\le m\)时,\(gcd(i,j)=x\)的数量。

我们再记\(F_x=\sum_{x|i}f_i\)

莫名其妙想到了莫比乌斯反演,但是在这里显然不能用

我们发现\(F(x)\)其实就是满足\(1\le i\le n,1\le j\le m,i|x,j|x\)\((i,j)\)数量,即\(\lfloor\frac{n}{x}\rfloor\lfloor\frac{m}{x}\rfloor\)

我们还发现\(f_i=F_i-\sum_{x=2}^{\lfloor\frac{n}{i}\rfloor}f_{xi}\),即\(F_i\)减去 \(f_k\)的和 ,其中\(k\)\(i\)的倍数且不等于\(i\)

于是我们从大到小枚举\(i\)并计算\(f_i\),答案就是\(\sum_{i=1}^n(2\times i-1)\times f_i\)

根据调和级数,其时间复杂度为\(O(nlogn)\)

code:

#include<bits/stdc++.h>
using namespace std;
int n,m;
long long num[100010],ans;
int main(){
    scanf("%d%d",&n,&m),n<m?swap(n,m),0:0;
    for(int i=n;i>=1;--i){
        num[i]=1ll*(n/i)*(m/i);
        for(int j=i+i;j<=n;j+=i)num[i]-=num[j];
        ans+=(2*i-1)*num[i];
    }
    printf("%lld",ans);
    return 0;
}

转载于:https://www.cnblogs.com/xryjr233/p/BZOJ2005.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值