zoukankan      html  css  js  c++  java
  • LOJ6229 这是一道简单的数学题

    这是一道简单的数学题

    [F(n)=sum_{i=1}^nsum_{j=1}^ifrac{mathrm{lcm}(i,j)}{mathrm{gcd}(i,j)} ]

    其中,(mathrm{lcm}(a,b)) 表示 (a)(b) 的最小公倍数,(mathrm{gcd}(a,b)) 表示 (a)(b) 的最大公约数。

    给定 (n) ,让你求: (F(n) mod1000000007)

    对于所有数据,(1 le n le 10^9)

    题解

    [F(n)=sum_{i=1}^nsum_{j=1}^i frac{ij}{gcd(i,j)^2}\ =sum_{d=1}^nsum_{i=1}^{lfloorfrac{n}{d} floor}sum_{j=1}^i ij[gcd(i,j)=1]\ =sum_{d=1}^nsum_{x=1}^{lfloorfrac{n}{d} floor}mu(x)x^2sum_{i=1}^{lfloorfrac{n}{dx} floor}sum_{j=1}^i ij\ =sum_{d=1}^n G(lfloorfrac{n}{d} floor) ]

    [G(n)=sum_{x=1}^nmu(x)x^2sum_{i=1}^{lfloorfrac{n}{x} floor}sum_{j=1}^i ij\ =sum_{x=1}^n mu(x)x^2 H(lfloorfrac{n}{x} floor) ]

    (mu(x)x^2) 的前缀和可以用杜教筛计算。

    [H(n)=sum_{i=1}^nsum_{j=1}^i ij\ =sum_{i=1}^n ifrac{(i+1)i}{2}\ =frac{1}{2}((frac{n(n+1)}{2})^2+frac{1}{6}n(n+1)(2n+1)) ]

    这样做有两层数论分块,而且第二层数论分块还套了一个杜教筛,跑的很慢。

    CO int N=1e7+10;
    int pri[N],tot,val[N];
    unordered_map<int,int> vs;
    
    int H(int n){
    	int ans=fpow(mul(n,mul(n+1,i2)),2);
    	ans=add(ans,mul(n,mul(n+1,mul(2*n+1,i6))));
    	ans=mul(ans,i2);
    	return ans;
    }
    int S(int n){
    	if(n<N) return val[n];
    	if(vs.count(n)) return vs[n];
    	int ans=1;
    	for(int l=2,r;l<=n;l=r+1){
    		r=n/(n/l);
    		int c=mul(r,mul(r+1,mul(2*r+1,i6)));
    		c=add(c,mod-mul(l-1,mul(l,mul(2*l-1,i6))));
    		ans=add(ans,mod-mul(c,S(n/l)));
    	}
    	return vs[n]=ans;
    }
    int G(int n){
    	int ans=0;
    	for(int l=1,r;l<=n;l=r+1){
    		r=n/(n/l);
    		int c=add(S(r),mod-S(l-1));
    		ans=add(ans,mul(c,H(n/l)));
    	}
    	return ans;
    }
    int F(int n){
    	int ans=0;
    	for(int l=1,r;l<=n;l=r+1){
    		r=n/(n/l);
    		ans=add(ans,mul(r-l+1,G(n/l)));
    	}
    	return ans;
    }
    
    int main(){
    	val[0]=0,val[1]=1;
    	for(int i=2;i<N;++i){
    		if(!pri[i]){
    			pri[++tot]=i;
    			val[i]=mod-mul(i,i);
    		}
    		for(int j=1;j<=tot and i*pri[j]<N;++j){
    			pri[i*pri[j]]=1;
    			if(i%pri[j]==0){
    				val[i*pri[j]]=0;
    				break;
    			}
    			val[i*pri[j]]=mul(val[i],val[pri[j]]);
    		}
    	}
    	for(int i=1;i<N;++i) val[i]=add(val[i],val[i-1]);
    	printf("%d
    ",F(read<int>()));
    	return 0;
    }
    

    可以观察到一个事实:莫比乌斯反演的辅助函数是 (varphi) 的计算方式是比辅助函数是 (mu) 的计算方式快的。

    [F(n)=sum_{d=1}^n sum_{i=1}^{lfloorfrac{n}{d} floor}isum_{j=1}^ij[gcd(i,j)=1]\ =sum_{d=1}^n sum_{i=1}^{lfloorfrac{n}{d} floor}ifrac{[i=1]+ivarphi(i)}{2}\ =frac{n+sum_{i=1}^nvarphi(i)i^2lfloorfrac{n}{i} floor}{2} ]

    这样只有一个数论分块套杜教筛,用时约为上一种做法的五分之一。

    复杂度分析

    注意整除分块的写法:

    for(int l=1,r;l<=n;l=r+1){
    	r=n/(n/l);
    	int c=add(S(r),mod-S(l-1));
    	ans=add(ans,mul(c,n/l));
    }
    

    注意到r=n/(n/l),所以r仍然是 (lfloorfrac{n}{x} floor) 的形式。那么S的结果也就能用数组存储。

    分析时间复杂度时可以认为S里面根号个值是预处理出来的。所以时间复杂度是 (O(n^{frac{2}{3}}+n^{frac{1}{2}}))

    我懒得改上面用unordered_map的代码了。

  • 相关阅读:
    LeetCode34 Search for a Range
    LeetCode32 Longest Valid Parentheses
    LeetCode33 Search in Rotated Sorted Array
    LeetCode31 Next Permutation
    LeetCode30 Substring with Concatenation of All Words
    LeetCode29 Divide Two Integers
    2016 Multi-University Training Contest 8
    2016 Multi-University Training Contest 9
    Gym 100285G Cipher Message 3
    背包九讲
  • 原文地址:https://www.cnblogs.com/autoint/p/12400783.html
Copyright © 2011-2022 走看看