给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的
数对(x,y)有多少对.
给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的
数对(x,y)有多少对.
一个整数N
如题
hint
对于样例(2,2),(2,4),(3,3),(4,2)
1<=N<=10^7
题意:给一个正整数 N,其中1<=N<=10^7,求使得 gcd(x,y)为质数的 (x,y)对的个数,1<=x,y<=n。
分析:莫比乌斯反演,十分的巧妙。
GCD(a,b)的题十分经典。GCD(a,b)=d (d是素数),但是思想却是相同的。
设f(d) = GCD(a,b) = d的种类数 ;
F(n) 为GCD(a,b) = d 的倍数的种类数,GCD(a,b)%d==0;
即 :F(x) = (N/x)*(N/x);//N中是x的倍数的个数,然后组合
则f(x) = sigma( mu[d/x]*F(d), d|n )
由于d = 1 所以f(1) = sigma( mu[d]*F(p*d) ) = sigma( mu[d]*(N/pd)*(N/pd) ); p为枚举的素数;p*d<N; (优化!否则会超时)
so....
初探莫比乌斯。还有很多不是很懂。跟进中。。。
转载请注明出处:寻找&星空の孩子
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2818
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 1e7+10; typedef long long LL; //LL F[MAXN],f[MAXN]; LL pri[MAXN],pri_num; LL mu[MAXN];//莫比乌斯函数值 bool vis[MAXN]; void mobius(int N) //筛法求莫比乌斯函数 { pri_num = 0;//素数个数 memset(vis, false, sizeof(vis)); vis[1] = true; mu[1] = 1; for(int i = 2; i <=N; i++) { if(!vis[i]) { pri[pri_num++] = i; mu[i] = -1; } for(int j=0; j<pri_num && i*pri[j]<N ; j++) { vis[i*pri[j]]=true;//标记非素数 //eg:i=3,i%2,mu[3*2]=-mu[3]=1;----;i=6,i%5,mu[6*5]=-mu[6]=-1; if(i%pri[j])mu[i*pri[j]] = -mu[i]; else { mu[i*pri[j]] = 0; break; } } } } int main() { // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); LL n; mobius(10000000); while(~scanf("%lld",&n)) { LL ans = (LL)0; for(LL i=0; pri[i]<=n; i++) { for(LL j=1; j<=n/pri[i]; j++) ans+=(LL)(mu[j]*((n/pri[i])/j)*((n/pri[i])/j)); } printf("%lld\n",ans); } return 0; }
我的代码跑了7秒。。。学长的代码跑了6秒。。。仅供参考
/* Language: C++ Result: Accepted Time:6432 ms Memory:167288 kb ****************************************************************/ #include<iostream> #include<stdio.h> #include<cstring> #include<cstdlib> using namespace std; typedef long long LL; const int maxn = 1e7+1; bool s[maxn]; int prime[maxn],len = 0; int mu[maxn]; int g[maxn]; int sum1[maxn]; void init() { memset(s,true,sizeof(s)); mu[1] = 1; for(int i=2; i<maxn; i++) { if(s[i] == true) { prime[++len] = i; mu[i] = -1; g[i] = 1; } for(int j=1; j<=len && (long long)prime[j]*i<maxn; j++) { s[i*prime[j]] = false; if(i%prime[j]!=0) { mu[i*prime[j]] = -mu[i]; g[i*prime[j]] = mu[i] - g[i]; } else { mu[i*prime[j]] = 0; g[i*prime[j]] = mu[i]; break; } } } for(int i=1; i<maxn; i++) sum1[i] = sum1[i-1]+g[i]; } int main() { int a; init(); while(scanf("%d",&a)>0) { LL sum = 0; for(int i=1,la = 0 ; i<=a; i = la+1) { la = a/(a/i); sum = sum + (long long)(sum1[la] - sum1[i-1])*(a/i)*(a/i); } printf("%lld\n",sum); } return 0; }
网上有其他的解法。。。还快些(5秒)
转载自:http://www.cnblogs.com/chensiang/p/4682706.html
/************************************************************** Problem: 2818 Language: C++ Result: Accepted Time:5220 ms Memory:128224 kb ****************************************************************/ #include<bits/stdc++.h> #define clr(a,x) memset(a,x,sizeof(a)) #define rep(i,l,r) for(int i=l;i<r;i++) typedef long long ll; using namespace std; // 欧拉函数 int read() { char c=getchar(); int ans=0,f=1; while(!isdigit(c)){ if(c=='-') f=-1; c=getchar(); } while(isdigit(c)){ ans=ans*10+c-'0'; c=getchar(); } return ans*f; } const int maxn=10000009; bool p[maxn]; ll f[maxn]; int s[maxn],cnt,n; void getphi() { rep(i,1,n+1) f[i]=i; rep(i,2,n+1){ if(f[i]==i){ for(int j=i;j<=n;j+=i){ f[j]=f[j]/i*(i-1); } } } rep(i,2,n+1) f[i]+=f[i-1]; } void getsushu() { clr(p,-1); p[1]=0; rep(i,2,(n>>1)+1){ if(p[i]){ for(int j=i<<1;j<=n;j+=i){ p[j]=0; } } } rep(i,2,n+1){ if(p[i]){ s[cnt++]=i; } } } int main() { n=read(); getphi(); getsushu(); ll ans=0; rep(i,0,cnt){ ans+=f[n/s[i]]*2-1; } printf("%lld\n",ans); return 0; }
mada...mada...!!!