• ●BZOJ 2693 jzptab


    题链:

    http://www.lydsy.com/JudgeOnline/problem.php?id=2693

    题解:

    莫比乌斯反演

    先看看这个题,BZOJ 2154 Crash的数字表格,本题的升级版:改为了多组数据。

    既然是多组数据,那么之前的$O(N)$的方法就不行了。

    现在需要对求ANS的式子进行优化,看看能不能降低复杂度。

    $ANS=sum_{g=1}^{min(n,m)}g imes sum_{d=1}^{min(lfloor frac{n}{g} floor,lfloor frac{m}{g} floor)} mu(d)d^2sum(lfloor frac{n}{gd} floor,lfloor frac{m}{gd} floor)$

    令$D=gd$,然后去枚举D,则

    $quadquad=sum_{D=1}^{min(n,m)}sum(lfloor frac{n}{D} floor,lfloor frac{m}{D} floor) sum_{d|D} frac{D}{d}mu(d)d^2$

    $quadquad=sum_{D=1}^{min(n,m)}sum(lfloor frac{n}{D} floor,lfloor frac{m}{D} floor) sum_{d|D} dD imesmu(d)$

    令$w[D]=sum_{d|D} dD imesmu(d)$,所以

    $ANS=sum_{D=1}^{min(n,m)}sum(lfloor frac{n}{D} floor,lfloor frac{m}{D} floor) w[D]$

    如果可以求出$w[D]$的值,那么这个求ANS的式子就可以用上向下取整的特性,以$O(sqrt N)$的复杂度求出。

    而至于$w[D]$求法,注意到这个也是积性函数,可以在线性筛时求出:

    1.对于一个质数p,$w[p]=1 imes p imes 1+p imes p imes(-1)$

    2.对于枚举到的i和质数p,

      如果i%p!=0,则运用积性函数的性质:$w[i imes p]=w[i] imes w[p]$

      否则,不难发现,新增的p导致产生的其他加项中$mu(d)=0$,所以直接$w[i imes p]=w[i] imes p$

    (w[ ]的推导仔细想想哈,其实并不麻烦的)

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define MAXN 10000050
    using namespace std;
    const int mod=100000009;
    int w[MAXN],pw[MAXN];
    void Sieve(){
    	static bool np[MAXN];
    	static int prime[MAXN],pnt;
    	w[1]=1,pw[1]=1;
    	for(int i=2;i<=10000000;i++){
    		if(!np[i]) prime[++pnt]=i,w[i]=((1ll*i-1ll*i*i%mod)%mod+mod)%mod;
    		for(int j=1;j<=pnt&&i<=10000000/prime[j];j++){
    			np[i*prime[j]]=1;
    			if(i%prime[j]) w[i*prime[j]]=((-1ll*w[i]*prime[j]%mod*prime[j]%mod+mod)%mod+1ll*w[i]*prime[j]%mod)%mod;
    			else{w[i*prime[j]]=1ll*w[i]*prime[j]%mod; break;}
    		}
    		pw[i]=(1ll*pw[i-1]+w[i])%mod;
    	}
    }
    int sum(int n,int m){
    	return ((1ll*(1+n)*n/2%mod)*(1ll*(1+m)*m/2%mod))%mod;
    }
    int main(){
    	Sieve(); int Case,n,m,ans,mini;
    	scanf("%d",&Case);
    	for(int i=1;i<=Case;i++){
    		scanf("%d%d",&n,&m);
    		ans=0; mini=min(n,m);
    		for(int d=1,last;d<=mini;d=last+1){
    			last=min(n/(n/d),m/(m/d));
    			ans=(1ll*ans+1ll*(pw[last]-pw[d-1]+mod)%mod*sum(n/d,m/d)%mod)%mod;
    		}
    		printf("%d
    ",(ans+mod)%mod);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    (十六)字段表集合
    (十五)类索引
    (十四)访问标志 Access_flags
    (一)单例模式
    (二十三)IDEA 构建一个springboot工程,以及可能遇到的问题
    (十三)class文件结构:常量池(转)
    Hive优化
    标签整理
    一些学习资料
    jstree树形菜单
  • 原文地址:https://www.cnblogs.com/zj75211/p/8274596.html
Copyright © 2020-2023  润新知