题意:
给出若干的元素,求从集合中选出任意某些元素,求他们的gcd*元素个数的和。要求gcd>1
思路:
第一次做莫比乌斯的题,感觉还是挺像模板题的。
f(x) = Σmu[d/x] *F(d)
其中mu[d/x]可以用筛法打素数表的时候处理出来。而F(d)则表示了因数为d的元素有多少个。
f(x)表示最大共因数为x的有多少个!
而对于任意的一个gcd 我们可以很容易知道,题目中要求我们得到的东西是
1*C(n,1) + 2*C(n,2) +.. i*C(n,i) +... n*C(n,n)= n*2^(n-1)。我们处理出的这个东西便是公式的F(d)。之后累计求每个f(x)的和
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1000005;
typedef long long ll;
long long vis[maxn];
long long mu[maxn];
long long prime[maxn];
long long pcnt;
long long a[maxn];
long long cot[maxn];
ll mod = 1e9 + 7;
void Init()
{
memset(vis, 0, sizeof(vis));
mu[1] = 1;
pcnt = 0;
for (long long i = 2; i<maxn; i++)
{
if (!vis[i])
{
prime[pcnt++] = i;
mu[i] = -1;
}
for (long long j = 0; j<pcnt&&i*prime[j]<maxn; j++)
{
vis[i*prime[j]] = 1;
if (i%prime[j]) mu[i*prime[j]] = -mu[i];
else
{
mu[i*prime[j]] = 0;
break;
}
}
}
}
ll quick(ll n, ll m)
{
ll z=1;
while(m)
{
if(m&1)
z=z*n%mod;
n*=n;
n%=mod;
m>>=1;
}
return z;
}
int main()
{
Init();
int n;
scanf("%d",&n);
int maxx=-1;
for(int i=1;i<=n;i++)
{
int t;
scanf("%d",&t);
a[t]++;
maxx=max(maxx,t);
}
for(int i=2;i<=maxx;i++)
{
for(int j=i;j<=maxx;j+=i)
cot[i]+=a[j];
}
for(int i=2;i<=maxx;i++)
{
if(cot[i])
cot[i]=cot[i]*quick(2,cot[i]-1)%mod;
}
ll ans=0;
for(ll i=2;i<=maxx;i++)
{
ll res=0;
for(ll j=1;j*i<=maxx;j++)
res+=mu[j]*cot[j*i];
ans+=res*i;
ans%=mod;
}
printf("%lld\n",ans);
}