Luogu P1447 [NOI2010]能量采集 数论??欧拉
作者:互联网
刚学的欧拉反演(在最后)就用上了,挺好$qwq$
题意:求$\sum_{i=1}^{N}\sum_{j=1}^{M}(2*gcd(i,j)-1)$
原式
$=2*\sum_{i=1}^{N}\sum_{j=1}^{M}gcd(i,j)\space-m*n$
$=2*\sum_{i=1}^{N}\sum_{j=1}^M\sum_{d|gcd(i,j)}\varphi(d)\space-m*n$
$=2*\sum_{i=1}^{\lfloor \frac{N}{d}\rfloor}\sum_{j=1}^{\lfloor \frac{M}{d} \rfloor}\sum_{d=1}^N\varphi(d)\space-m*n$
$=2*\sum_{d=1}^N\varphi(d)\lfloor \frac{N}{d}\rfloor \lfloor \frac{M}{d} \rfloor \space-m*n$
所以又可以整除分块+线性筛$\varphi(n)$前缀和$
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<cctype> #include<cstdlib> #include<vector> #include<queue> #include<map> #include<set> #define ll long long #define R register int using namespace std; namespace Fread { static char B[1<<15],*S=B,*D=B; #define getchar() (S==D&&(D=(S=B)+fread(B,1,1<<15,stdin),S==D)?EOF:*S++) inline int g() { R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix; do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix; } }using Fread::g; const int N=100010; ll p[N],pri[N],cnt; bool v[N]; inline void PHI(int n) { p[1]=1; for(R i=2;i<=n;++i) { if(!v[i]) pri[++cnt]=i,p[i]=i-1; for(R j=1;j<=cnt&&i*pri[j]<=n;++j) { v[i*pri[j]]=true; if(i%pri[j]==0) { p[i*pri[j]]=pri[j]*p[i]; break; } p[i*pri[j]]=p[i]*p[pri[j]]; } } for(R i=1;i<=n;++i) p[i]+=p[i-1]; } int n,m; ll ans; signed main() { #ifdef JACK freopen("NOIPAK++.in","r",stdin); #endif PHI(100000); n=g(),m=g(); n>m?swap(n,m):void(0); for(R l=1,r;l<=n;l=r+1) { r=min(n/(n/l),m/(m/l)); ans+=(ll)2*(p[r]-p[l-1])*(n/l)*(m/l); } printf("%lld\n",ans-(ll)n*m); }
2019.06.09
标签:lfloor,P1447,space,Luogu,sum,rfloor,NOI2010,varphi,include 来源: https://www.cnblogs.com/Jackpei/p/10993237.html