题解 SP4191 【MSKYCODE - Sky Code】
Tommy_clas · · 题解
我终于见到第一个会用莫比乌斯函数的题了(反演菜鸡
这道题比较适合初学容斥的人做。
传送门
题目大意:给出
“互质”也就要求最大公约数为
总之问题就转化成了从
因为最多有
对于这种有很多限制的题目,我们可以考虑一下容斥。
既然我们考虑的是对于每一个质因子都不能全部整除四个数,那我们可以反过来考虑一下至少有某些质因子全部整除四个数。至于为什么这样考虑,是因为这是根据容斥原理的公式和内容类比得来的。其实是懒得打公式(逃。
因此,我们能得到如下等式:
每个质因子都不全能整除的方案数=不带限制的总方案数
-至少一个质因子全能整除的方案数
+至少两个质因子全能整除的方案数
-至少三个质因子全能整除的方案数
......以此类推。
这样问题又转化成了如何求至少有某些质因子全部整除四个数的方案数。先求出
怎么去求数量?暴力枚举质因子的组合然后暴力统计?显然时间并不够用。
其实我们忘记了一个时间复杂度与调和级数有关的求一些数的同一个约数的总个数的方法。那就是枚举约数,然后再在值域内枚举它的倍数,统计它是
然后我们只需要从所有枚举的约数里,找到需要的约数即可。(质因子分解后每个幂的指数都是
但是还记得我们开头说了什么吗?
所有数的统计答案直接乘上对应的莫比乌斯函数再求和即是正确答案!
因为对于质因子幂的指数不为
总而言之,我们先预处理出
上代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#define N 10005
#define ll long long
using namespace std;
int n,sum[N],maxn,prime[N];
ll ans;
int tag[N],mo[N],vis[N];
void init()
{
mo[1]=1;
for(int i=2;i<=N-5;i++)
{
if(!vis[i])mo[i]=-1,prime[++prime[0]]=i;
for(int j=1;prime[j]*i<=N-5&&j<=prime[0];j++)
{
vis[i*prime[j]]=1;
if(i%prime[j])mo[i*prime[j]]=mo[i]*(-1);
else break;
}
}
}
void clean()
{
maxn=ans=0;
memset(tag,0,sizeof(tag));
memset(sum,0,sizeof(sum));
}
ll C(ll a,ll b)
{
if(a<b)return 0;
if(b==0)return 1;
ll res=1;
for(ll i=0;i<b;i++)res*=a-i;
for(ll i=1;i<=b;i++)res/=i;
return res;
}
int main()
{
init();
while(scanf("%d",&n)!=EOF)
{
clean();
for(int i=1,x;i<=n;i++)
scanf("%d",&x),maxn=max(maxn,x),tag[x]=1;
for(int i=1;i<=maxn;i++)
for(int j=i;j<=maxn;j+=i)
if(tag[j])sum[i]++;
for(int i=1;i<=maxn;i++)
ans+=mo[i]*C(sum[i],4);
printf("%lld\n",ans);
}
return 0;
}