码迷,mamicode.com
首页 > 其他好文 > 详细

●BZOJ 2005 NOI 2010 能量采集

时间:2017-12-01 20:45:01      阅读:115      评论:0      收藏:0      [点我收藏+]

标签:一个   www   pen   turn   最大公约数   bar   als   mes   多少   

题链:

http://www.lydsy.com/JudgeOnline/problem.php?id=2005

题解:

一个带有容斥思想的递推。
%%%
首先,对于一个点 (x,y) 在路径 (0,0)->(x,y)上,经过的点数为 GCD(x,y)-1
所以改点的贡献为 2*GCD(x,y)-1
            N    M
那么,ANS = ∑    ∑(2*GCD(i,j)-1)
           i=1 j=1
显然超时。
考虑到 GCD<=100000,
那么是否可以求出 f[i] 表示 GCD==i的点对 (x,y)有多少个。
然后用f[i]去得出答案 (ans+=f[i]*(2*i-1))?
 
接下来就是神奇的递推了。
f[i]=(N/i)*(M/i) - f[i*k]  (i*k<=min(N,M))
上式中 (N/i)*(M/i) 求得的是 有i这个公约数的点对(x,y)的个数
因为这些点对的最大公约数GCD可能为 i,2i,3i......
所以减掉f[2i],f[3i],f[4i]......就得到了f[i].

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
using namespace std;
ll f[100005];
ll N,M,K,ans;
int main()
{
	freopen("energy.in","r",stdin);
	freopen("energy.out","w",stdout);
	cin>>N>>M; K=min(N,M);
	for(int i=K;i>=1;i--){
		f[i]=(N/i)*(M/i);
		for(int j=2;i*j<=K;j++)
			f[i]-=f[i*j];
		ans+=f[i]*(2*i-1);
	}
	printf("%lld",ans);
	return 0;
}

●BZOJ 2005 NOI 2010 能量采集

标签:一个   www   pen   turn   最大公约数   bar   als   mes   多少   

原文地址:http://www.cnblogs.com/zj75211/p/7944189.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!