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

上一篇:「NOI2010」超级钢琴


下一篇:题解 【NOI2010】超级钢琴