zoukankan      html  css  js  c++  java
  • 线性筛,积性函数,狄利克雷卷积,常见积性函数的筛法

    一些性质

    • 积性函数:对于函数(f(n)),若满足对任意互质的数字(a,b,a*b=n)(f(n)=f(a)f(b)),那么称函数f为积性函数。
    • 狄利克雷卷积:对于函数f,g,定义它们的卷积为
      ((f∗g)(n)=sum_{d|n}f(d)g(frac{n}{d}))
      狄利克雷卷积满足很多性质:
      交换律:(f∗g=g∗f)
      结合律:((f∗g)∗h=f∗(g∗h))
    • 两个积性函数的狄利克雷卷积仍为积性函数。
    • 积性函数都可以用线性筛筛出来

    怎么筛?
    (一般来讲,只要知道f(P^k),P为质数,就可以知道怎么筛了)
    (简单来讲就是推一下)
    (通俗来讲就是手玩一下或者打表找规律)
    如果你一眼就看出来了那就只能Orz了

    几道题

    Bzoj4804: 欧拉心算
    BZOJ2693jzptab
    BZOJ4407 :于神之怒加强版

    一些常见积性函数的筛法

    莫比乌斯函数(mu(n))

    这个比较简单,(mu(1)=1)(i)为质数时(mu(i)=-1),最小质因子筛到它的时候正负号反过来,否则为(0)

    
    	isprime[1] = 1; mu[1] = 1;
    	for(int i = 2; i < N; ++i){
    		if(!isprime[i]){  prime[++num] = i; mu[i] = -1;  }
    		for(int j = 1; j <= num && i * prime[j] < N; ++j){
    			isprime[i * prime[j]] = 1;
    			if(i % prime[j]) mu[i * prime[j]] = -mu[i];
    			else{  mu[i * prime[j]] = 0; break;  }
    		}
    	}
    

    乘法逆元(inv(i))

    求一个数在模p意义下的逆元
    (p=i*x+j),则(i*x+jequiv0(mod p))
    同时除以(i*j,所以x*j^{-1}+i^{-1}equiv0(mod p))
    移项(i^{-1}equiv-x*j^{-1}(mod p))
    (x=p div i,j=p mod i)
    所以(inv(i)=-inv(p\%i)*(p/i))
    不用筛了,递推就可以了

    inv[1] = 1; for(int i = 2; i < p; ++i) inv[i] = -(p / i) * inv[p % i] % p + p) % p;
    

    补充阶乘逆元的递推,求出(inv(n))(inv(i)=inv(i+1)*(i+1))倒着来就行了

    fac[0] = inv[0] = 1;
    for(int i = 1; i <= n; ++i) fac[i] = fac[i] * i % p;
    inv[n] = Getinv(fac[n]); //Exgcd or Fermat
    for(int i = 1; i < n; i++) inv[i] = inv[i + 1] * (i + 1) % p;
    

    欧拉函数(varphi(n))

    公式:
    (n分解成若干质数p的乘积n=Pi p_i^{a_i})
    (varphi(n)=n*Pi(1-frac{1}{p_i}))

    那么(varphi(1)=1)(n为质数时varphi(n)=n-1),最小质因子筛到它时乘上质因子(p-1),否则乘上这个质数

    isprime[1] = 1; phi[1] = 1;
    	for(int i = 2; i < N; ++i){
    		if(!isprime[i]){  prime[++num] = i; phi[i] = i - 1;  }
    		for(int j = 1; j <= num && i * prime[j] < N; ++j){
    			isprime[i * prime[j]] = 1;
    			if(i % prime[j]) phi[i * prime[j]] = phi[i] * (prime[j] - 1);
    			else{  phi[i * prime[j]] = phi[i] * prime[j]; break;  }
    		}
    	}
    

    约数个数(d(n))

    公式:
    还是分解
    (d(n)=Pi(a_i + 1))

    我们记录下每个数最小质因子的指数记为(pred)就好了

    isprime[1] = 1; d[1] = 1;
    for(int i = 2; i < N; ++i){
    	if(!isprime[i]){  prime[++num] = i; d[i] = 2; pred[i] = 1;  }
    	for(int j = 1; j <= num && i * prime[j] < N; ++j){
    		isprime[i * prime[j]] = 1;
    		if(i % prime[j]){
    			d[i * prime[j]] = d[i] * d[prime[j]];
    			pred[i * prime[j]] = 1;
    		}
    		else{
    			pred[i * prime[j]] = pred[i] + 1;
    			d[i * prime[j]] = d[i] / (pred[i] + 1) * (pred[i] + 2);
    			break; 
    		}
    	}
    }
    

    约数的和(sigma(n))

    公式:
    又是分解
    (sigma(n)=Pi(sum_{j=0}^{a_i}p_i^j))

    这个就很烦了。。。

    也可以筛,开两个个数组,一个(powd)记录每个数最小质因子的指数次幂,另一个(sumd)记录每个数最小质因子(sum_{i=0}^{a}p^i)就可以了

    我们把这个鬼里鬼气的(sigma写成f)

    isprime[1] = 1; f[1] = mu[1] = 1;
    for(int i = 2; i < N; ++i){
    	if(!isprime[i]){
    		prime[++num] = i; f[i] = i + 1; mu[i] = -1;
    		sumd[i] = 1 + i; powd[i] = i;
    	}
    	for(int j = 1; j <= num && i * prime[j] < N; ++j){
    		isprime[i * prime[j]] = 1;
    		if(i % prime[j]){
    			sumd[i * prime[j]] = 1 + prime[j];
    			powd[i * prime[j]] = prime[j];
    			f[i * prime[j]] = f[i] * f[prime[j]];
    		}
    		else{
    			powd[i * prime[j]] = powd[i] * prime[j];
    			sumd[i * prime[j]] = sumd[i] + powd[i * prime[j]];
    			f[i * prime[j]] = f[i] / sumd[i] * sumd[i * prime[j]];
    			break;
    		}
    	}
    }
    

    完结

  • 相关阅读:
    nyoj 139 我排第几个--康拓展开
    树形dp--hdu 3534 Tree
    hdu 2196 Computer 树形dp模板题
    poj 2342 Anniversary party 简单树形dp
    hdu 4738 Caocao's Bridges 图--桥的判断模板
    poj 1144 Network 图的割顶判断模板
    poj 3159 Candies 差分约束
    poj 3169 Layout 差分约束模板题
    codeforces C. Triangle
    java中过滤器、监听器、拦截器的区别
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/8268373.html
Copyright © 2011-2022 走看看