ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

POJ3094 Sky Code(莫比乌斯反演)

2019-05-07 22:52:10  阅读:361  来源: 互联网

标签:Code 四元组 int Sky ret mu 反演 maxn include


POJ3094 Sky Code(莫比乌斯反演)

Sky Code

题意

给你\(n\le 10^5\)个数,这些数\(\le 10^5\),问这些这些数组成的互不相同的无序四元组(a,b,c,d)使得gcd(a,b,c,d)=1的四元组有多少?

解法

枚举一个约数\(k\),看看总共有多少个数\(S_k=\{x\}\)满足\(k|x\)。那么可以保证(a,b,c,d)有的一个共同的因子是k,这样的四元组的个数就是
\[ F(k)={|S_k|\choose 4} \]
这样算会算重,比如枚举到\(k=4\)再枚举到\(k=2\),这两者的方案显然有重复,加入有一个四元组满足有一个共同约数是4,那么他们一定也可以满足有一个共同约数是2。我们记\(f(x)=\)最大公因数是\(x\)的四元组的数量。上面的那个大\(F(x)\)就表示有一个公因数(不是最大公因数)是\(x\)的四元组的数量

我们数学模型化这个算重的关系:
\[ F(n)=\Sigma_{d|x}f(d) \]
这不就是莫比乌斯反演可以解决的嘛 piece of cake
\[ f(x)=\Sigma_{x|d}\mu(d)F(d) \]
那么(看不懂请右上角)
\[ \Sigma f(x)=\Sigma_i\mu(i)F(i) \]
Q:你这样不是O(n^2)吗,你怎么实现可以在正确的复杂度内得到每个数所有的因数?

A:开个桶表示每个\(|S_k|\),枚举\(i\in 2-\sqrt x\),把\(i\)和\(x/i\)都丢在桶里计数。复杂度\(O(n^{1.5})\)注意当\(i=x/i\)的时候只算一次!

//@winlere
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;  typedef long long ll;
template < class ccf > inline ccf qr(ccf ret){      ret=0;
      register char c=getchar();
      while(not isdigit(c)) c=getchar();
      while(isdigit(c)) ret=ret*10+c-48,c=getchar();
      return ret;
}

const int maxn=1e4+1;
ll c[maxn][5];
int n;
ll ans;
int buk[maxn];
int cnt[maxn];
bool data[maxn];
int mu[maxn];
bool usd[maxn];
vector < int > ve;

inline void pr(){
      usd[1]=1;mu[1]=0;
      for(register int t=2;t<maxn;++t){
        if(not usd[t]) ve.push_back(t),mu[t]=-1;
        for(register int i=0,edd=ve.size();i<edd;++i){
          register int k=ve[i];
          if(1ll*k*t>maxn)break;
          usd[k*t]=1;
          if(t%k==0) break;
          mu[k*t]=-mu[t];
        }
      }
}


int main(){
      c[0][0]=1;
      pr();
      for(register int t=1;t<maxn;++t){
        c[t][0]=1;
        for(register int i=1;i<=4;++i)
          c[t][i]=c[t-1][i-1]+c[t-1][i];
      }
      while(~scanf("%d",&n)){
        ans=c[n][4];
        memset(buk,0,sizeof buk);
        for(register int t=1,data;t<=n;++t){
          ++buk[data=qr(1)];
          for(register int i=2;i*i<=data;++i)
            if(data%i==0)
                  if(++buk[i],data/i!=i) ++buk[data/i];
        }
        for(register int t=1;t<maxn;++t)
          if(buk[t]>=4&&mu[t])
            ans+=mu[t]*c[buk[t]][4];
        printf("%lld\n",ans);
      }
      return 0;
}

标签:Code,四元组,int,Sky,ret,mu,反演,maxn,include
来源: https://www.cnblogs.com/winlere/p/10828681.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有