zoukankan      html  css  js  c++  java
  • [BZOJ 3930] [CQOI 2015]选数(莫比乌斯反演+杜教筛)

    [BZOJ 3930] [CQOI 2015]选数(莫比乌斯反演+杜教筛)

    题面

    我们知道,从区间([L,R])(L和R为整数)中选取N个整数,总共有((R-L+1)^N)种方案。求最大公约数刚好为K的选取方案有多少个。由于方案数较大,你只需要输出其除以1000000007的余数即可。

    [N,K,L,H leq 10^9,H-L leq 10^5 ]

    分析

    (ecause gcd(ka,kb)=kgcd(a,b)),我们先把(L,R)除以(K),然后问题就变成了求gcd=1的方案数

    (f(x))表示区间[l,r]里选n个数,gcd为x的方案数

    (F(x))表示区间[l,r]里选n个数,gcd被x整除的方案数

    (ecause x|gcd(i,j), herefore x|i,x|j)

    [l,r]里被x整除的数有((lfloor frac{r}{x} floor-lfloor frac{l-1}{x} floor))

    因此(F(x)=(lfloor frac{r}{x} floor-lfloor frac{l-1}{x} floor)^n)

    (F,f)显然满足莫比乌斯反演的第二种形式,(F(x)=sum_{d|x} f(d))

    (f(x)=sum_{x|d} F(d) mu(frac{d}{x}))

    我们要求的是

    [f(1)=sum_{1|d} F(d) mu(d)=sum_{d=1}^r mu(d) (lfloor frac{r}{d} floor-lfloor frac{l-1}{d} floor)^n ]

    后面的部分可以数论分块然后快速幂求解,但由于(r leq 10^9),不能直接线性筛(mu)的前缀和,需要用杜教筛。


    杜教筛:

    套路公式:

    我们要求(f)的前缀和,构造两个函数(g,h)满足(h=f*g), (F,G,H)为它们的前缀和

    [g(1)F(n)=H(n)-sum_{d=2}^n g(d) F(frac{n}{d}) ]

    如果(f=mu),注意到(mu*I=varepsilon),那么(g(n)=I(n)=1,h(n)=varepsilon(n),H(n)=varepsilon(1)=1)

    代入得(F(n)=1-sum_{d=2}^n F(frac{n}{d}))

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<map>
    #define maxn 2000000
    #define mod 1000000007
    using namespace std;
    typedef long long ll;
    int n,k;
    ll A,B;
    
    int cnt;
    bool vis[maxn+5];
    int prime[maxn+5];
    int mu[maxn+5];
    ll s_mu[maxn+5];
    void sieve(int n){
    	mu[1]=1;
    	for(int i=2;i<=n;i++){
    		if(!vis[i]){
    			prime[++cnt]=i;
    			mu[i]=-1;
    		} 
    		for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
    			vis[i*prime[j]]=1;
    			if(i%prime[j]==0){
    				mu[i*prime[j]]=0;
    				break;
    			}else mu[i*prime[j]]=-mu[i];
    		}
    	}
    	for(int i=1;i<=n;i++) s_mu[i]=(s_mu[i-1]+mu[i])%mod;
    }
    
    map<ll,ll>sum_mu;
    ll dujiao_sieve(ll x){
    	if(x<=maxn) return s_mu[x];
    	if(sum_mu.count(x)) return sum_mu[x];
    	ll ans=1;
    	for(ll l=2,r;l<=x;l=r+1){
    		r=x/(x/l);
    		ans-=(r-l+1)*dujiao_sieve(x/l)%mod;
    		ans=(ans+mod)%mod;
    	}
    	sum_mu[x]=ans;
    	return ans;
    } 
    
    inline ll fast_pow(ll x,ll k){
    	ll ans=1;
    	while(k){
    		if(k&1) ans=ans*x%mod;
    		x=x*x%mod;
    		k>>=1;
    	}
    	return ans;
    }
    
    int main(){
    	sieve(maxn);
    	scanf("%d %d %lld %lld",&n,&k,&A,&B);
    	A=(A-1)/k;
    	B/=k;
    	ll ans=0;
    	for(ll l=1,r;l<=B;l=r+1){
    		if(A/l) r=min(A/(A/l),B/(B/l));
    		else r=B/(B/l);
    //		printf("%d %d
    ",l,r);
    		ans+=fast_pow(B/l-A/l,n)*(dujiao_sieve(r)-dujiao_sieve(l-1)+mod)%mod;
    		ans%=mod;
    	}
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    影响指令流水线的因素
    硬布线控制器和微程序控制器 
    总线仲裁
    计算机专业面试
    P、NP、NPC、NPH问题的区别和联系
    多态
    软件生命周期
    你所不知道的js的小知识点(1)
    html span标签 不换行(有时span带中文时候是可以自动换行的)
    form的onsubmit事件--表单提交前的验证最佳实现方式
  • 原文地址:https://www.cnblogs.com/birchtree/p/11438266.html
Copyright © 2011-2022 走看看