NOI2010 能量采集 解题报告

来源:互联网 发布:风险矩阵法公式 编辑:程序博客网 时间:2024/05/21 18:46

【题目大意】:一个n*m的网格,将这n*m个点分别与原点连线(坐标轴上无点),如果一个点与原点连接而成的线段上有k个点,那么该点的     得分为2*k+1,总得分为这n*m个点的得分和。给你n和m,求总得分。

::点击图片在新窗口中打开::

这是一个样例,每个点上都标明了该点的得分,总的得分为36。


对于10%的数据:1 ≤ n, m ≤ 10;
对于50%的数据:1 ≤ n, m ≤ 100;
对于80%的数据:1 ≤ n, m ≤ 1000;
对于90%的数据:1 ≤ n, m ≤ 10,000;
对于100%的数据:1 ≤ n, m ≤ 100,000。



首先可以看出,对于每一对点(x,y),如果有另外一对点(x',y'),且x/y=x'/y',那么它们肯定是共线的。

然后我发现,由于数据范围过大,肯定不能通过枚举来确定每个点的分数,于是我就转而寻找每个点本身的某个性质,而这个性质可以决定其连线上点的个数。

经过对样例中每个点的观察,我发现对于每个点(x,y),它连线上的点的个数为gcd(x,y),证明如下:

对于一对(x,y),且gcd(x,y)=1,则(d*x,d*y)(d*x<=n,d*y<=m)与x,y在同一条连线上,而(d*x,d*y)的连线上有d个点.又因为gcd(d*x,d*y)=d,且每对(x',y')都可以表示为(d*x,d*y)的形式,所以上述假设成立。


然后原问题转化为求,所以就要求所有gcd(i,j)的和。


再次观察发现,所求问题的域较大(n*m),而答案的域较小(min(n,m)),所以一个很重要的转化就是对于与每一个d(<min(m,n)),求出有多少对gcd(x,y)=d,而对于这个问题,可以利用容斥原理解决。


首先,令f[d]表示最大公约数为d的(x,y)的对数,公约数里有d的(x,y)对数共有([n/d]*[m/d])对,然后要排出里面公约数有大于d的(x,y)对数,要排出多少个? --> f[d*2]+f[d*3]+...+f[d*k](d*k<=min(n,m))个。


这样,我们可以用逆推的方式求出所有的gcd(x,y)之和,然后代入推出的公式中就可以得到答案,时间复杂度度为O(nlgn)。

 

 

原创粉丝点击