2818: Gcd
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1566 Solved: 691
[Submit][Status]
Description
给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的
数对(x,y)有多少对.
Input
一个整数N
Output
如题
Sample Input
Sample Output
HINT
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...!!!