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) );
}