zoukankan      html  css  js  c++  java
  • [BZOJ2154][洛谷P1829]Crash的数字表格(莫比乌斯反演+基础应用:消gcd)

    题面

    https://www.luogu.com.cn/problem/P1829

    题解

    前置知识

    要求({sum_{i=1}^{n}}{sum_{j=1}^{m}}[i,j])

    首先转化成为({sum_{i=1}^{n}}{sum_{j=1}^{m}}{frac{ij}{(i,j)}})

    求和中化解gcd的小技巧

    假设我们遇到求和({sum_{i=1}^{n}}{sum_{j=1}^{m}}f((i,j))),其中f是某给定函数。

    那么我们可以设函数(g = f { imes} {mu}),则由莫比乌斯反演,有(f=g{ imes}I)。(此处及以下“({ imes})”表示狄利克雷卷积)然后做如下转化:

    [{sum_{i=1}^{n}}{sum_{j=1}^{m}}f((i,j)) ]

    [={sum_{i=1}^{n}}{sum_{j=1}^{m}}{sum_{d|(i,j)}}g(d) ]

    由于有(d|(i,j))等价于(d|i)(d|j)的性质,可以进一步化简为:

    [={sum_{i=1}^{n}}{sum_{j=1}^{m}}{sum_{d|i,d|j}}g(d) ]

    [={sum_d}g(d){sum_{i=1}^{n}}{sum_{j=1}^{m}}[d|i][d|j] ]

    [={sum_d}g(d)({sum_{i=1}^{n}}[d|i])({sum_{j=1}^{m}}[d|j]) ]

    [={sum_d}g(d){{lfloor}{frac{n}{d}}{ floor}}{lfloor}{frac{m}{d}}{ floor} ]

    即完成了gcd的化简。

    如果求和是({sum_{i=1}^{n}}{sum_{j=1}^{m}}g(i)h(j)f((i,j))),过程也如出一辙,只要

    [g(d)+g(2d)+…+g({lfloor}{frac{n}{d}}{ floor}d) ]

    [h(d)+h(2d)+…+h({lfloor}{frac{m}{d}}{ floor}d) ]

    能够快速处理,也能够适用此方法。

    回本题。此题中(f(x) = {frac{1}{x}})

    [{sum_{i=1}^{n}}{sum_{j=1}^{m}}ijf((i,j)) ]

    [={sum_{i=1}^{n}}{sum_{j=1}^{m}}ij{sum_{d|(i,j)}}g(d) ]

    [={sum_{i=1}^{n}}{sum_{j=1}^{m}}ij{sum_{d|i,d|j}}g(d) ]

    [={sum_{d}}g(d){sum_{i=1}^{n}}{sum_{j=1}^{m}}[d|i][d|j]ij ]

    [={sum_{d}}g(d)({sum_{i=1}^{n}}[d|i]i)({sum_{j=1}^{n}}[d|j]j) ]

    注意到两个括号内分别是

    [d+2d+…+{lfloor}{frac{n}{d}}{ floor}d ]

    [d+2d+…+{lfloor}{frac{m}{d}}{ floor}d ]

    这两个等差数列之和,于是原式=

    [{sum_d}g(d)d^2({frac{1}{2}}{lfloor}{frac{n}{d}}{ floor}({lfloor}{frac{n}{d}}{ floor}+1))({frac{1}{2}}{lfloor}{frac{m}{d}}{ floor}({lfloor}{frac{m}{d}}{ floor}+1)) ]

    其中

    [g(d)={sum_{p|d}}f({frac{d}{p}}){mu}(p) ]

    [={sum_{p|d}}{frac{p}{d}}{mu(p)} ]

    为了避免出现小数或者分数,简化计算,我们令(h(d)=d*g(d))

    那么有

    [h(d)={sum_{p|d}}p{mu(p)} ]

    这是一个积性函数,可以线性求出。同时有原式=

    [{sum_d}h(d)d({frac{1}{2}}{lfloor}{frac{n}{d}}{ floor}({lfloor}{frac{n}{d}}{ floor}+1))({frac{1}{2}}{lfloor}{frac{m}{d}}{ floor}({lfloor}{frac{m}{d}}{ floor}+1)) ]

    可以枚举d,O(min(n,m))求解。

    代码

    #include<bits/stdc++.h>
    
    using namespace std;
    
    #define N 10000000
    #define rg register
    #define mod 20101009
    #define F(x) (1ll*x*(x+1)/2%mod)
    
    namespace ModCalc{
    	inline void Inc(int &x,int y){
    		x += y;if(x > mod)x -= mod; 
    	}
    	
    	inline void Dec(int &x,int y){
    		x -= y;if(x < 0)x += mod;
    	}
    	
    	inline void Tms(int &x,int y){
    		x = 1ll * x * y % mod;
    	}
    	
    	inline int Add(int x,int y){
    		Inc(x,y);return x;
    	}
    	
    	inline int Sub(int x,int y){
    		Dec(x,y);return x;
    	}
    	
    	inline int Mul(int x,int y){
    		Tms(x,y);return x;
    	}
    }
    using namespace ModCalc;
    
    int pn;
    int pri[1200000+5];
    bool isp[N+5];
    int h[N+5];
    int P[N+5]; //P[i]表示i的素因数分解式中底数最小的那一项的大小 
    
    inline void Eular(){ //线性筛h[]
    	pn = 0;
    	h[1] = 1;
    	for(rg int i = 2;i <= N;i++)isp[i] = 1;
    	for(rg int i = 2;i <= N;i++){
    		if(isp[i]){
    			pri[++pn] = i;
    			P[i] = i;
    			h[i] = mod + 1 - i;
    		} 
    		for(rg int j = 1;i * pri[j] <= N;j++){
    			isp[i*pri[j]] = 0;
    			if(i % pri[j]){
    				P[i*pri[j]] = pri[j];
    				h[i*pri[j]] = Mul(h[i],h[pri[j]]);
    			}	
    			else{
    				int I = i * pri[j];
    				P[I] = Mul(P[i],pri[j]);
    				if(P[I] == I)h[I] = h[i];
    				else h[I] = Mul(h[I/P[I]],h[P[I]]); 
    				break;
    			} 
    		}
    	}
    }
    
    int n,m;
    
    int main(){
    	Eular();
    	scanf("%d%d",&n,&m);
    	int ans = 0;
    	int M = min(n,m);
    	for(rg int d = 1;d <= M;d++)Inc(ans,1ll*h[d]*d%mod*F(n/d)%mod*F(m/d)%mod);
    	cout << ans << endl;
    	return 0;
    }
    
  • 相关阅读:
    Python-枚举
    Python-函数
    Python-装饰器(语法糖)上下五千年和前世今生
    Python-全局函数(内置方法、内置函数)
    Python-时间模块-time
    Python-随机模块-random
    Python-维护排序好的序列模块-bisect
    需求推动技术的产生
    RBF神经网络
    聚类算法的衡量指标
  • 原文地址:https://www.cnblogs.com/xh092113/p/12268356.html
Copyright © 2011-2022 走看看