• POJ3094 Sky Code(莫比乌斯反演)


    POJ3094 Sky Code(莫比乌斯反演)


    Sky Code

    题意

    给你(nle 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(x)=Sigma_{x|d}f(d) ]

    这不就是莫比乌斯反演可以解决的嘛 piece of cake

    [f(x)=Sigma_{x|d}mu(d)F(frac d x) ]

    那么把(f(1))求出来就好了

    Q:你这样不是O(n^2)吗,你怎么实现可以在正确的复杂度内得到每个数所有的因数?

    A:开个桶表示每个(|S_k|),枚举(iin [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
    ",ans);
          }
          return 0;
    }
    
  • 相关阅读:
    JS给数字加千位分隔符
    前端防抖与节流实现与应用
    JS实现单向链表、双向链表、循环链表
    单点登录
    AMD、CMD规范
    JS实现全排列
    event loop、进程和线程、任务队列
    BOM属性对象方法
    JS的闭包、高阶函数、柯里化
    for...in、for...of、forEach()有什么区别
  • 原文地址:https://www.cnblogs.com/winlere/p/10828681.html
Copyright © 2020-2023  润新知