【数论-莫比乌斯】小练

xiaoxiao2021-02-28  228

2005: [Noi2010]能量采集

题意:有一二维平面n*m,从(0,0)开始看,到每个点的贡献为(gcd(i,j)-1)*2+1,求总贡献; 思路:枚举gcd,二维平面优化复杂度O(sqrt(n)+sqrt(m)); if(n>m) swap(n,m)  代码: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define mod 1000000007 #define ll long long const int N=300100; bool check[N+10]; int prime[N+10]; int mu[N+10]; void Moblus() { memset(check,false,sizeof(check)); mu[1]=1; int tot=0; for(int i=2; i<=N; i++) { if(!check[i]) { prime[tot++]=i; mu[i]=-1; } for(int j=0; j<tot; j++) { if(i*prime[j]>N) break; check[i*prime[j]]=true; if(i%prime[j]==0) { mu[i*prime[j]]=0; break; } else { mu[i*prime[j]]=-mu[i]; } } } } int sum[N+10]; ll solve(int n,int m) { ll ans=0; for(int i=1,la=0;i<=n;i=la+1) { la=min(n/(n/i),m/(m/i)); ans+=(ll)(sum[la]-sum[i-1])*(n/i)*(m/i); } return ans; } int main() { Moblus(); sum[0]=0; for(int i=1;i<=N;i++) sum[i]=sum[i-1]+mu[i]; int n,m; while(~scanf("%d%d",&n,&m)) { if(n>m) swap(n,m); ll ans=0; for(int i=1;i<=n;i++) { int n1=n/i,m1=m/i; ll an=solve(n1,m1); ans+=an*((i-1)*2+1); } printf("%lld\n",ans); } return 0; }

2818: Gcd

题意:给定整数N,求1<=x,y<=N 且Gcd(x,y) 为素数的数对(x,y)有多少对? 思路:枚举素数,和上题一样 代码: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define mod 1000000007 #define ll long long const int N=10000010; bool check[N+10]; int prime[N+10]; int mu[N+10]; int tot=0; void Moblus() { memset(check,false,sizeof(check)); mu[1]=1,tot=0; for(int i=2; i<=N; i++) { if(!check[i]) { prime[tot++]=i; mu[i]=-1; } for(int j=0; j<tot; j++) { if(i*prime[j]>N) break; check[i*prime[j]]=true; if(i%prime[j]==0) { mu[i*prime[j]]=0; break; } else { mu[i*prime[j]]=-mu[i]; } } } } int sum[N+10]; ll solve(int n,int m) { ll ans=0; for(int i=1,la=0; i<=n; i=la+1) { la=min(n/(n/i),m/(m/i)); ans+=(ll)(sum[la]-sum[i-1])*(n/i)*(m/i); } return ans; } int main() { Moblus(); // printf("%d\n",tot); sum[0]=0; for(int i=1; i<=N; i++) sum[i]=sum[i-1]+mu[i]; int n,m; while(~scanf("%d",&n)) { m=n; ll ans=0; for(int i=0; i<tot; i++) { int n1=n/prime[i],m1=m/prime[i]; ll an=solve(n1,m1); ans+=an; } printf("%lld\n",ans); } return 0; }

SQFREE - Square-free integers

题意:Square-free integer:无平方因子数。输入n,求1~n的无平方因子数个数; 思路:容斥+莫比乌斯函数; 当然容斥公式是别人的: [1,x] 之间的无平方因子数个数: 对于sqrt(x) 以内所有的质数, 有x以内的无平方因子数=0个质数乘积的平方的倍数的数的数量(1的倍数)                                           - 每个质数的平方的倍数的数的数量(4的倍数,9的倍数,25的倍数...)                                          + 每2个质数乘积的平方的倍数的数的数量(36的倍数,100的倍数...)                                          ........ 公式: 参考blog: 点击打开链接 代码: #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; #define mod 1000000007 #define ll long long const int N=10000010; bool check[N+10]; int prime[N+10]; int mu[N+10]; int tot=0; void Moblus() { memset(check,false,sizeof(check)); mu[1]=1,tot=0; for(int i=2; i<=N; i++) { if(!check[i]) { prime[tot++]=i; mu[i]=-1; } for(int j=0; j<tot; j++) { if(i*prime[j]>N) break; check[i*prime[j]]=true; if(i%prime[j]==0) { mu[i*prime[j]]=0; break; } else { mu[i*prime[j]]=-mu[i]; } } } } int main() { Moblus(); int t; scanf("%d",&t); while(t--) { ll n; scanf("%lld",&n); ll x=sqrt(n); ll ans=0; for(ll i=1; i<=x;i++) { ans+=mu[i]*(n/i/i); } printf("%lld\n",ans); } return 0; }

2440: [中山市选2011]完全平方数

题意:求第k个无平方因子数; 思路:二分答案,然后用上题作为判断条件; 代码: #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> using namespace std; #define mod 1000000007 #define ll long long const int N=100010; bool check[N+10]; int prime[N+10]; int mu[N+10]; int tot=0; void Moblus() { memset(check,false,sizeof(check)); mu[1]=1,tot=0; for(int i=2; i<=N; i++) { if(!check[i]) { prime[tot++]=i; mu[i]=-1; } for(int j=0; j<tot; j++) { if(i*prime[j]>N) break; check[i*prime[j]]=true; if(i%prime[j]==0) { mu[i*prime[j]]=0; break; } else { mu[i*prime[j]]=-mu[i]; } } } } ll solve(ll x,ll n) { ll ans=0; for(ll i=1; i<=x; i++) { ans+=mu[i]*(n/i/i); } return ans; } int main() { Moblus(); int t; scanf("%d",&t); while(t--) { int k; scanf("%d",&k); ll l=1,r=10000000000; // printf("%lld\n",mid); while(l<r) { ll mid=(l+r)>>1; if(solve(sqrt(mid),mid)<k) l=mid+1; else r=mid; // printf("%lld %lld\n",l,r); } printf("%lld\n",l); } return 0; }
转载请注明原文地址: https://www.6miu.com/read-18526.html

最新回复(0)