【莫比乌斯】 BZOJ 2005 能量采集
思路:
可以证明点(x,y)与(0,0)所连线段上不包含原点有的点为gcd(x,y)
于是问题就变成了求gcd(x,y)(1 <= x <= n,1 <= y <= m)的和;
可以设f[i]表示gcd为i的点对数有多少
首先公因数里面有i的点对数显然是(n / i) * ( m / i)
然后再减去f[i的倍数]就得到了f[i]
代码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #define inf 0x7fffffff #define ll long long using namespace std; inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } ll n,m; ll ans,f[100005]; int main() { n=read();m=read(); if(n<m)swap(n,m); for(ll i=n;i;i--) { f[i]=(n/i)*(m/i); for(ll j=2*i;j<=n;j+=i) f[i]-=f[j]; ans+=f[i]*(2*i-1); } printf("%lld",ans); return 0; }