[BZOJ2005]NOI2010能量采集|数学

来源:互联网 发布:js 双引号转单引号 编辑:程序博客网 时间:2024/04/28 21:30

数学题。。首先要知道点(x,y)与原点连线上整点的个数为gcd(x,y)(除原点)。我们可以找到最小的(x0,y0)在连线上,显然gcd(x0,y0)=1,那么所有(x0*k,y0*k)(x0*k<=n)都会在连线上,显然k最大为gcd(x,y),得证。其实还是很好想的,需要一点对函数的感觉。。根据这个可以枚举(x,y)算gcd,不过只能过8个点。。这样的话,可以考虑倒过来计算gcd为d的点数,直接不好算,我们先计算以d为公约数的点对数g[d],根据乘法原理显然g[d]=[n/d]*[m/d]。然后计算gcd为d的点对数f[d],只需要把公约数为d但还有大于d的公约数的点去掉就行了,所以可以得到f[d]=g[d]-∑f[k*d](k>=2&&k*d<=n),这个式子根据第一个结论的思路就可以想到。。

#include<iostream>#include<cstdio>#define ll long longusing namespace std;ll g[100005],f[100005],ans;int i,j,n,m; int main(){scanf("%d%d",&n,&m);if (m>n) swap(m,n);ans=0ll;for (i=m;i;i--){f[i]=(ll)(m/i)*(ll)(n/i);for (j=2;j<=m/i;j++) f[i]-=f[j*i];ans+=f[i]*(ll)(2*i-1);}cout<<ans;}


0 0