HYSBZ 2818 莫比乌斯函数(不能化1的情况)

给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的
数对(x,y)有多少对.

Input
一个整数N

Output
如题

Sample Input
4

Sample Output
4
Hint
hint

对于样例(2,2),(2,4),(3,3),(4,2)

1<=N<=10^7

莫比乌斯里面的 u(i) 是 取的素数的组合的前面的正负号 就是 u(1)-u(2)-u(3)-u(5)+u(6)…

重点:gcd(x,y)=k 转化成 gcd(x/k,y//k) == 1 的情况下,这个时候 n/k 是指的全部数量,但是这时候会有 gcd 为1的倍数的情况,所以利用莫比乌斯(容斥来排除)最好用的就是化为1的情况 不能化为1就想办法化1。反正就是对个数进行容斥。

还有就是这题的测评鸡有问题 我暴力求 比网上的优化速度快= =

#include <bits/stdc++.h>
using namespace std;

const int maxn=1e7+10;  
bool vis[maxn];  
int prime[maxn],mu[maxn];  
int cnt;  
typedef long long ll;

void Init(){  
    int N=maxn;  
    memset(prime,0,sizeof(prime));  
    memset(mu,0,sizeof(mu));  
    memset(vis,0,sizeof(vis));  
    mu[1] = 1;  
    cnt = 0;  
    for(int i=2; i<N; i++){  
        if(!vis[i]){  
            prime[cnt++] = i;  
            mu[i] = -1;  
        }  
        for(int j=0; j<cnt&&i*prime[j]<N; j++){  
            vis[i*prime[j]] = 1;  
            if(i%prime[j]) mu[i*prime[j]] = -mu[i];  
            else{  
                mu[i*prime[j]] = 0;  
                break;  
            }  
        }  
    }
  }

ll cal(int x,int n)
{
    ll anss=0;
    n/=x;
    for(int i=1;i<=n;i++)
        anss+=(ll)mu[i]*(n/i)*(n/i);
    return anss;
}

int main()
{
    int n;
    scanf("%d",&n);
    long long ans=0;
    Init();
    for(int i=0;i<cnt&&prime[i]<=n;i++)
    {
        ans+=cal(prime[i],n);
    }
    printf("%lld\n",ans );
}

网上的优化 就是 如果能整除 sum[i*prime[j]]=mu[i];
如果不能整除,就是如果可以整除 就是一个整体,不然就只能
sum[i*prime[j]]=mu[i]-sum[i]; 对于那些不能化1的情况 就这么处理

#include <bits/stdc++.h>
using namespace std;

const int maxn=1e7+10;  
bool vis[maxn];  
int prime[maxn],mu[maxn];  
int cnt;  
typedef long long ll;
ll sum[maxn];
void Init(){  
    int N=maxn;  
    memset(prime,0,sizeof(prime));  
    memset(mu,0,sizeof(mu));  
    memset(vis,0,sizeof(vis));  
    mu[1] = 1;  
    cnt = 0;  
    for(int i=2; i<N; i++){  
        if(!vis[i]){  
            prime[cnt++] = i;  
            sum[i]=1;
            mu[i] = -1;  
        }  
        for(int j=0; j<cnt&&i*prime[j]<N; j++){  
            vis[i*prime[j]] = 1;  
            if(i%prime[j])
            { 
                mu[i*prime[j]] = -mu[i];  
                sum[i*prime[j]]=mu[i]-sum[i];
            }
            else{  
                mu[i*prime[j]] = 0;  
                sum[i*prime[j]]=mu[i];
                break;  
            }  
        }  
    }
  }



ll work(int n)
{
    ll anss=0;
    for(int i=2;i<=n;i++)
    {
        anss+=(ll)(n/i)*(ll)(n/i)*sum[i];
    }
    return anss;
}

int main()
{
    int n;
    long long ans=0;
    Init();
    while(scanf("%d",&n)!=EOF)
    printf("%lld\n",work(n) );
}
posted @ 2017-09-19 21:18  黑码的博客  阅读(79)  评论(0编辑  收藏  举报