zoukankan      html  css  js  c++  java
  • BZOJ 2005 能量采集

    Description

    栋栋有一块长方形的地,他在地上种了一种能量植物,这种植物可以采集太阳光的能量。在这些植物采集能量后,栋栋再使用一个能量汇集机器把这些植物采集到的能量汇集到一起。 栋栋的植物种得非常整齐,一共有(n)列,每列有(m)棵,植物的横竖间距都一样,因此对于每一棵植物,栋栋可以用一个坐标((x,y))来表示,其中(x)的范围是(1)(n),表示是在第(x)列,(y)的范围是(1)(m),表示是在第(x)列的第(y)棵。 由于能量汇集机器较大,不便移动,栋栋将它放在了一个角上,坐标正好是((0,0))。能量汇集机器在汇集的过程中有一定的能量损失。如果一棵植物与能量汇集机器连接而成的线段上有k棵植物,则能量的损失为(2k+1)。例如,当能量汇集机器收集坐标为((2,4))的植物时,由于连接线段上存在一棵植物((1,2)),会产生(3)的能量损失。注意,如果一棵植物与能量汇集机器连接的线段上没有植物,则能量损失为1。现在要计算总的能量损失。 下面给出了一个能量采集的例子,其中(n=5,m=4),一共有(20)棵植物,在每棵植物上标明了能量汇集机器收集它的能量时产生的能量损失。在这个例子中,总共产生了36的能量损失。

    Input

    仅包含一行,为两个整数(n)(m)

    Output

    仅包含一个整数,表示总共产生的能量损失。

    Sample Input

    5 4

    Sample Output

    36

    HINT

    对于(10\%)的数据:(1 le n,m le 10)
    对于(50\%)的数据:(1 le n, m le 100)
    对于(80\%)的数据:(1 le n, m le 1000)
    对于(90\%)的数据:(1 le n, m le 10000)
    对于(100\%)的数据:(1 le n, m le 100000)

    题目求$$sum_{i=1}^{N} sum_{j=1}^{M}2 imes gcd(i,j) - 1$$
    转换变成枚举(gcd)求$$sum_{g=1}^{min(N,M)}(2 imes g -1)sum_{i = 1}^{N} sum_{j = 1}^{M} [gcd(i,j) = g]$$
    然后同BZOJ 2301 Problem b的做法进行莫比乌斯反演,就可以化成$$sum_{g=1}{min(N,M)}sum_{k=1}{min(lfloor frac{N}{g} floor,lfloor frac{M}{g} floor)} mu(k) lfloor frac{N}{kg} floor lfloor frac{M}{kg} floor $$
    由于$$sum_{i=1}^{N} frac{1}{i} approx ln N$$
    所以直接求这个式子复杂度是(O(NlogN))
    由于人比较愚钝,所以我预处理了(mu)的前缀和,还傻逼的(sqrt{N})分段了。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    
    typedef long long ll;
    #define maxn 100010
    int n,m,tot,prime[maxn],mu[maxn];
    bool exist[maxn]; ll ans;
    
    inline void find()
    {
    	mu[1] = 1;
    	for (int i = 2;i <= n;++i)
    	{
    		if (!exist[i]) prime[++tot] = i,mu[i] = -1;
    		for (int j = 1;j <= tot&&i*prime[j]<=n;++j)
    		{
    			exist[i*prime[j]] = true;
    			if (i % prime[j] == 0) { mu[i*prime[j]] = 0; break; }
    			mu[i*prime[j]] = -mu[i];
    		}
    	}
    	for (int i = 1;i <= n;++i) mu[i] += mu[i-1];
    }
    
    inline ll calc(int a,int b,int d)
    {
    	a /= d; b /= d;
    	ll ret = 0; int pos;
    	for (int i = 1;i <= a;i = pos+1)
    	{
    		pos = min(a/(a/i),b/(b/i));
    		ret += (ll)(mu[pos]-mu[i-1])*(ll)(a/i)*(ll)(b/i);
    	}
    	return ret;
    }
    
    int main()
    {
    	freopen("2005.in","r",stdin);
    	freopen("2005.out","w",stdout);
    	scanf("%d %d",&n,&m); if (n > m) swap(n,m);	
    	find();
    	for (int i = 1;i <= n;++i)
    		ans += (ll)((i<<1)-1)*calc(n,m,i);
    	printf("%lld",ans);
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    【译】.NET 的新的动态检测分析
    【译】Visual Studio 的 Razor 编辑器的改进
    【译】.NET 5. 0 中 Windows Form 的新特性
    MySQL InnoDB 索引(Index)
    MySQL 全文检索(Full-Text Search)
    MySQL 计算最大值、最小值和中位数
    MySQL 触发器(Triggers)
    MySQL 视图(View)
    MySQL基础知识:MySQL String 字符串处理
    MySQL基础知识:MySQL Connection和Session
  • 原文地址:https://www.cnblogs.com/mmlz/p/4631220.html
Copyright © 2011-2022 走看看