[NOI2010][bzoj2005] 能量采集 [欧拉函数+分块前缀和优化]
Posted Orion545
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NOI2010][bzoj2005] 能量采集 [欧拉函数+分块前缀和优化]相关的知识,希望对你有一定的参考价值。
题面:
思路:
稍微转化一下,可以发现,每个植物到原点连线上植物的数量,等于gcd(x,y)-1,其中xy是植物的横纵坐标
那么我们实际上就是要求2*sigma(gcd(x,y))-n*m了
又有某不知名神奇定理:一个数的所有因子的phi之和等于这个数本身,其中phi是欧拉函数
因此题目转化为求如下:
我们把式子变个型,就成了如下式子:
然后一个前缀和优化,O(n+sqrt(n))解决
Code:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #define ll long long 6 using namespace std; 7 inline ll read(){ 8 ll re=0,flag=1;char ch=getchar(); 9 while(ch>\'9\'||ch<\'0\'){ 10 if(ch==\'-\') flag=-1; 11 ch=getchar(); 12 } 13 while(ch>=\'0\'&&ch<=\'9\') re=(re<<1)+(re<<3)+ch-\'0\',ch=getchar(); 14 return re*flag; 15 } 16 ll phi[100010],pri[100010],cnt,pre[100010]; 17 void init(){ 18 phi[1]=pre[1]=1;ll i,j,k; 19 for(i=2;i<=100010;i++){ 20 if(!phi[i]) phi[i]=i-1,pri[++cnt]=i; 21 for(j=1;(j<=cnt)&&(i*pri[j]<=100010);j++){ 22 if(i%pri[j]) phi[i*pri[j]]=phi[i]*(pri[j]-1); 23 else{phi[i*pri[j]]=phi[i]*pri[j];break;} 24 } 25 pre[i]=pre[i-1]+phi[i]; 26 // if(i<=10) cout<<"phi "<<i<<" "<<phi[i]<<"\\n"; 27 } 28 } 29 ll n,m;ll ans; 30 int main(){ 31 init();ll i,j; 32 n=read();m=read(); 33 if(n>m) swap(n,m); 34 for(i=1;i<=n;i=j+1){ 35 j=min(n/(n/i),m/(m/i)); 36 ans+=(ll)(n/i)*(m/i)*(pre[j]-pre[i-1]); 37 } 38 printf("%lld\\n",ans*2-n*m); 39 }
∑ni=1∑mi=1∑d
∑ni=1∑mi=1∑d
以上是关于[NOI2010][bzoj2005] 能量采集 [欧拉函数+分块前缀和优化]的主要内容,如果未能解决你的问题,请参考以下文章