CodeForces - 235E Number Challenge(莫比乌斯反演 + 数论分块)

mac2024-05-26  53

CodeForces - 235E Number Challenge

大致题意做法代码

大致题意

计算如下式子

做法

如果只是两个数字乘积的约数个数,那么有公式: σ ( i j ) = ∑ a ∣ i ∑ b ∣ j [ ( a , b ) = 1 ] \sigma(ij)=\sum_{a|i} \sum_{b|j}[(a,b)=1] σ(ij)=aibj[(a,b)=1] 当有三个数字的时候,我们同样大胆猜测然后打表验证,可以得到如下公式: σ ( i j k ) = Σ a ∣ i Σ b ∣ j Σ c ∣ k [ ( a , b ) = 1 ] [ ( a , c ) = 1 ] [ ( b , c ) = 1 ] \sigma(ijk)=\Sigma_{a|i} \Sigma_{b|j}\Sigma_{c|k}[(a,b)=1][(a,c)=1][(b,c)=1] σ(ijk)=ΣaiΣbjΣck[(a,b)=1][(a,c)=1][(b,c)=1] 那么本题就相当于计算 Σ i = 1 a Σ j = 1 b Σ k = 1 c   Σ x ∣ i Σ y ∣ j Σ z ∣ k [ ( x , y ) = 1 ] [ ( x , z ) = 1 ] [ ( y , z ) = 1 ] \Sigma_{i=1}^{a}\Sigma_{j=1}^{b}\Sigma_{k=1}^{c}\ \Sigma_{x|i} \Sigma_{y|j}\Sigma_{z|k}[(x,y)=1][(x,z)=1][(y,z)=1] Σi=1aΣj=1bΣk=1c ΣxiΣyjΣzk[(x,y)=1][(x,z)=1][(y,z)=1] 考虑交换求和次序,先枚举x、y和z,然后三个相互互质可以等价于其中两个互质,第三个数字与前两个数字的乘积互质,于是可以转化为如下式子: Σ x = 1 a Σ y = 1 b   ⌊ a x ⌋ ⌊ b y ⌋ [ ( x , y ) = 1 ]   Σ z = 1 c   ⌊ c z ⌋ [ ( x y , z ) = 1 ] \Sigma_{x=1}^{a}\Sigma_{y=1}^{b}\ \lfloor\frac{a}{x}\rfloor\lfloor\frac{b}{y}\rfloor [(x,y)=1]\ \Sigma_{z=1}^{c}\ \lfloor\frac{c}{z}\rfloor[(xy,z)=1] Σx=1aΣy=1b xayb[(x,y)=1] Σz=1c zc[(xy,z)=1] 我们令 f ( n , m ) = Σ i = 1 m   ⌊ m i ⌋ [ ( n , i ) = 1 ] f(n,m)=\Sigma_{i=1}^{m}\ \lfloor\frac{m}{i}\rfloor[(n,i)=1] f(n,m)=Σi=1m im[(n,i)=1],显然这个是可以反演的,反演之后有: f ( n , m ) = Σ d ∣ n m   μ ( d ) Σ i = 1 ⌊ m / d ⌋ ⌊ ⌊ m d ⌋ i ⌋ f(n,m)=\Sigma_{d|n}^{m}\ \mu(d) \Sigma_{i=1}^{\lfloor m/d \rfloor}\lfloor \frac{\lfloor\frac{m}{d}\rfloor}{i}\rfloor f(n,m)=Σdnm μ(d)Σi=1m/didm g ( n ) = Σ i = 1 n ⌊ n i ⌋ g(n)= \Sigma_{i=1}^{n}\lfloor \frac{n}{i}\rfloor g(n)=Σi=1nin,这个可以用数论分块在 O ( N ) O(\sqrt{N}) O(N )的时间复杂度内求出来。

那么 f ( n , m ) = Σ d ∣ n m   μ ( d ) g ( ⌊ m d ⌋ ) f(n,m)=\Sigma_{d|n}^{m}\ \mu(d)g(\lfloor\frac{m}{d}\rfloor) f(n,m)=Σdnm μ(d)g(dm)可以在 O ( M ) O(M) O(M)的时间复杂度内求出来。

进而对于所有的 f ( x y , z ) f(xy,z) f(xy,z),我们可以在 O ( N 2 ) O(N^2) O(N2)的时间复杂度内预处理出来。

这样,最后的答案就是: Σ x = 1 a Σ y = 1 b   ⌊ a x ⌋ ⌊ b y ⌋ [ ( x , y ) = 1 ]   f ( x y , z ) \Sigma_{x=1}^{a}\Sigma_{y=1}^{b}\ \lfloor\frac{a}{x}\rfloor\lfloor\frac{b}{y}\rfloor [(x,y)=1]\ f(xy,z) Σx=1aΣy=1b xayb[(x,y)=1] f(xy,z) 直接枚举i和j,判断 g c d ( i , j ) gcd(i,j) gcd(i,j)即可。总的时间复杂度为 O ( N 2 log ⁡ N ) O(N^2\log N) O(N2logN)。具体见代码。

代码

#include<bits/stdc++.h> #define fi first #define se second #define LL long long #define pb push_back #define INF 0x3f3f3f3f #define sc(x) scanf("%d",&x) #define scc(x,y) scanf("%d%d",&x,&y) #define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z) using namespace std; const int N = 2010; const int mod = 1 << 30; const int msk = mod - 1; int a,b,c,n,tot,p[N*N],mu[N*N],f[N],s[N*N]; bool isp[N*N]; void init(int N) { int sz=0; mu[1]=1; for(int i=2;i<N;i++) { if(!isp[i])p[++sz]=i,mu[i]=-1; for(int j=1;j<=sz&&(LL)i*p[j]<N;j++) { isp[i*p[j]]=1; if(i%p[j]==0) { mu[p[j]*i]=0; break; } else mu[p[j]*i]=-mu[i]; } } } int main() { sccc(a,b,c); init(a*b); for (int d=1;d<=c;d++) { int n=c/d; for (int l=1,r;l<=n;l=r+1) { r=n/(n/l); f[d]=(f[d]+(n/l)*(r-l+1))&msk; } } for (int i=1;i<=c;i++) { if (!mu[i]) continue; int w=mu[i]*f[i]; w+=w<0?mod:0; for (int j=i;j<=a*b;j+=i) s[j]=(s[j]+w)&msk; } int ans=0; for (int i=1;i<=a;i++) for (int j=1;j<=b;j++) if (__gcd(i,j)==1) ans=(ans+(LL)(a/i)*(b/j)*s[i*j]&msk)&msk; printf("%d",ans); return 0; }
最新回复(0)