P1447 [NOI2010] 能量采集

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1447 [NOI2010] 能量采集相关的知识,希望对你有一定的参考价值。

P1447 [NOI2010] 能量采集

题意:

如果一棵植物与能量汇集机器(坐标为0,0)连接而成的线段上有 k 棵植物,则能量的损失为 2k + 1
给你一个n*m的植物园,问能量损失是多少
1<=n,m<=1e5

题解:

本题所求式子为: ∑ i = 1 n ∑ j = 1 n g c d ( i , j ) ∗ 2 − 1 \\sum_{i=1}^{n}\\sum_{j=1}^{n}gcd(i,j)*2-1 i=1nj=1ngcd(i,j)21
式子如何求的?
参考这个AcWing 201. 可见的点
对于90%的数据,直接for循环就行
但是现在是acm赛制,要都过
本题思路参考这个,我只能说太秒了
设f[x]为gcd(i,j)=x的数对(i,j)的个数
答案就是 ∑ x = 1 n f [ x ] ∗ 2 − 1 \\sum_{x=1}^{n}f[x]*2-1 x=1nf[x]21
但是f[x]不好求啊
我们可以利用容斥来做
令g[x]为存在公因子=x的数对(i,j)的个数,注意不是最大公因数,而是存在公因子
g [ x ] = ⌊ n x ⌋ ∗ ⌊ m x ⌋ g[x]=\\lfloor \\frac{n}{x}\\rfloor*\\lfloor \\frac{m}{x}\\rfloor g[x]=xnxm
(1~n中是被x整除的数量为 ⌊ n x ⌋ \\lfloor \\frac{n}{x} \\rfloor xn
但是这些数中有一些最大公因数为2d,3d,4d,这些数重复添加,所以我们需要删去
所以:f[x]=g[x]- ∑ i ∗ x = 2 ∗ x m i n ( n , m ) f [ i ∗ x ] \\sum_{i*x=2*x}^{min(n,m)}f[i*x] ix=2xmin(n,m)f[ix]
从后向前枚举x,这样可以用已知的f[i*x]去更新f[x]
复杂度O(nlog n)

代码:

#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\\n", a, b);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
void read(){};
template <typename _Tp, typename... _Tps> void read(_Tp& x, _Tps&... Ar)
{
    x= 0;
    char c= getchar();
    bool flag= 0;
    while (c < '0' || c > '9')
        flag|= (c == '-'), c= getchar();
    while (c >= '0' && c <= '9')
        x= (x << 3) + (x << 1) + (c ^ 48), c= getchar();
    if (flag)
        x= -x;
    read(Ar...);
}
template <typename T> inline void write(T x)
{
    if (x < 0) {
        x= ~(x - 1);
        putchar('-');
    }
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}
void rd_test()
{
#ifdef ONLINE_JUDGE
#else
    startTime = clock ();
    freopen("in.txt", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#else
    endTime= clock();
    printf("\\nRun Time:%lfs\\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
const int N=100010;
int n,m;
ll f[N],ans;
ll g[N];
int main(){
	scanf("%d%d",&n,&m);
	if(n>m)swap(n,m);
	for(int i=n;i>=1;--i){
	    g[i]=1ll*(n/i)*(m/i);
	    for(int j=i*2;j<=n;j+=i)
			g[i]-=f[j];
		f[i]=g[i];
	    ans+=(i*2-1)*f[i];
	}
	printf("%lld",ans);
	return 0;
}


以上是关于P1447 [NOI2010] 能量采集的主要内容,如果未能解决你的问题,请参考以下文章

[NOI2010]能量采集

BZOJ2005: [Noi2010]能量采集

BZOJ 2005[Noi2010]能量采集

BZOJ 2005 [Noi2010]能量采集

bzoj 2005: [Noi2010]能量采集 筛法||欧拉||莫比乌斯

BZOJ2005[Noi2010]能量采集 欧拉函数