• 【2020杭电多校round6】HDU6833 A Very Easy Math Problem


    题目大意

    题目链接

    给定(k,x)(t)次询问,每次给出一个(n)。请你求:

    [sum_{a_1=1}^{n}sum_{a_2=1}^{n}ldots sum_{a_x=1}^{n}left (prod_{j=1}^{x}a_j^k ight )f(gcd(a_1,a_2,ldots ,a_x))cdot gcd(a_1,a_2,ldots ,a_x) ]

    (gcd(a_1,a_2,ldots ,a_n))(a_1,a_2,...,a_n)的最大公约数。

    函数(f(x))定义为:如果存在一个整数(k) ((k>1))使得(k^2)(x)的约数,则(f(x)=0),否则(f(x)=1)

    答案对(10^9+7)取模。

    数据范围:(1leq k,xleq 10^9)(1leq tleq 10^4)(1leq nleq 2 imes 10^5)

    本题题解

    先考虑单组数据的情况。

    可以计算每个(gcd)值的贡献。不过精确考虑“(gcd)等于”几有些困难,我们可以先对每个(d)求出“(gcd)(d)的倍数”的贡献,再容斥回去:

    // F[d] 表示gcd是d的倍数,对答案的贡献
    // 容斥成 G[d] 表示gcd就是d,对答案的贡献
    int ans=0;
    for(int d=n;d>=1;--d){
    	G[d]=F[d];
    	for(int j=d+d;j<=n;j+=d){
    		G[d]-=G[j];
    	}
    	ans+=G[d]*f[d]*d;
    }
    

    考虑钦定了(gcd)(d)的倍数,如何求出(sum_{a_1=1}^{n}sum_{a_2=1}^{n}ldots sum_{a_x=1}^{n}left (prod_{j=1}^{x}a_j^k ight )),也就是代码片段里的F[d]。此时的限制,就是所有(a_i)都要是(d)的倍数。可以先令所有(a_i)都除以(d),那剩下部分的取值,就只有([1,lfloorfrac{n}{d} floor]),每个(a_i)都能取这些值,那它们的乘积之和,就等于:((1^k+2^k+dots+lfloorfrac{n}{d} floor^k)^x)。再把所有的(d)乘回去,则(F[d]=d^{kx}(1^k+2^k+dots+lfloorfrac{n}{d} floor^k)^x)。求出F[]后,再用上面的代码容斥求出答案。

    但这只是单组数据时的做法。

    对多组数据,每次独立求答案是不现实的。我们考虑从(n-1)(n)递推答案,每次只需要计算这两者之间微小的变化。

    具体来说,要使(n)对新答案有影响,则(d)一定要是(n)的约数(否则(lfloorfrac{n}{d} floor=lfloorfrac{n-1}{d} floor),求出来的(F)值显然还是一样的)。那么我们每次枚举(n)的约数,时间复杂度相当于(1dots n)的约数数量之和,约等于(O(nlog n))(可以考虑每个数能作为哪些数的约数,显然是(i,2i,3idots ,lfloorfrac{n}{i} floorcdot i),所以数量是(frac{n}{i})(1dots n)的总数就是(sum_{i=1}^{n}frac{n}{i}),也就是调和级数)。

    现在,我们虽然能快速求出哪些(F)有变化,也能得到新的(F)值,但如果每次重新做一遍容斥,复杂度还是无法接受的。我们考虑把这个容斥转化一下,改成求出每个(F[d])在容斥里的贡献系数(c[d])。这样不管(F[d])怎么变化,我们只需要往答案里加上变化值( imes c[d])即可。

    (c[d])怎么求呢?可以先初始化,令(c[d]=f(d)cdot d)(这里的(f)是题面中定义的函数,千万不要与我们定义的大(F)搞混)。然后:

    for(int i=1;i<=n;++i)
    	c[i]=f[i]*i;
    for(int i=1;i<=n;++i){
    	for(int j=i+i;j<=n;j+=i){
    		c[j]-=c[i];
    	}
    }
    

    这是因为每个(F)值会在它的约数处被减掉。可以把这个代码对照上面的容斥理解,上面的容斥(求出的ans)就等价于(sum_{i=1}^{n}F[i]cdot c[i])。这就是我们求出这个系数(c)数组的妙处。

    于是我们就能(O(1))修改并更新答案了。

    总时间复杂度(O(nlog n+t))

    参考代码:

    //problem:
    #include <bits/stdc++.h>
    using namespace std;
    
    #define pb push_back
    #define mk make_pair
    #define lob lower_bound
    #define upb upper_bound
    #define fi first
    #define se second
    #define SZ(x) ((int)(x).size())
    
    typedef unsigned int uint;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    
    template<typename T>inline void ckmax(T& x,T y){x=(y>x?y:x);}
    template<typename T>inline void ckmin(T& x,T y){x=(y<x?y:x);}
    
    const int MOD=1e9+7;
    inline int mod1(int x){return x<MOD?x:x-MOD;}
    inline int mod2(int x){return x<0?x+MOD:x;}
    inline void add(int& x,int y){x=mod1(x+y);}
    inline void sub(int& x,int y){x=mod2(x-y);}
    inline int pow_mod(int x,int i){int y=1;while(i){if(i&1)y=(ll)y*x%MOD;x=(ll)x*x%MOD;i>>=1;}return y;}
    
    const int MAXN=2e5;
    
    int K,X,n;
    int pw[MAXN+5],sum[MAXN+5],pwX_of_pwK[MAXN+5],pwX_of_sum[MAXN+5];
    int F[MAXN+5],coef[MAXN+5],ans[MAXN+5];
    vector<int>factors[MAXN+5];
    
    int p[MAXN+5],cnt_p,f[MAXN+5];
    bool v[MAXN+5];
    void sieve(int lim){
    	f[1]=1;
    	for(int i=2;i<=lim;++i){
    		if(!v[i]){
    			p[++cnt_p]=i;
    			f[i]=1;
    		}
    		for(int j=1;j<=cnt_p && i*p[j]<=lim;++j){
    			v[i*p[j]]=1;
    			if(i%p[j]==0){
    				break;
    			}
    			if(f[i])
    				f[i*p[j]]=1;
    		}
    	}
    }
    void init(){
    	sieve(MAXN);
    	for(int i=1;i<=MAXN;++i){
    		pw[i]=pow_mod(i,K);
    		sum[i]=mod1(pw[i]+sum[i-1]);
    		pwX_of_pwK[i]=pow_mod(pw[i],X);
    		pwX_of_sum[i]=pow_mod(sum[i],X);
    	}
    }
    
    int main() {
    	int T;cin>>T>>K>>X;
    	init();
    	/*
    	//单组数据的简单容斥:
    	cin>>n;
    	for(int g=1;g<=n;++g){
    		F[g]=(ll)pow_mod(sum[n/g],X)*pow_mod(pw[g],X)%MOD;
    	}
    	int ans=0;
    	for(int i=n;i>=1;--i){
    		G[i]=F[i];
    		for(int j=i+i;j<=n;j+=i){
    			sub(G[i],G[j]);
    		}
    		ans=((ll)ans + (ll)G[i]*f[i]%MOD*i)%MOD;
    	}
    	cout<<ans<<endl;
    	*/
    	for(int i=1;i<=MAXN;++i)
    		coef[i]=f[i]*i;
    	for(int i=1;i<=MAXN;++i){
    		for(int j=i+i;j<=MAXN;j+=i){
    			sub(coef[j],coef[i]);
    		}
    	}
    	
    	ans[1]=F[1]=1;
    	for(int i=1;i<=MAXN;++i){
    		for(int j=i;j<=MAXN;j+=i){
    			factors[j].pb(i);
    		}
    	}
    	for(int i=2;i<=MAXN;++i){
    		ans[i]=ans[i-1];
    		for(int j=0;j<SZ(factors[i]);++j){
    			int g=factors[i][j];
    			sub(ans[i],(ll)F[g]*coef[g]%MOD);
    			F[g]=(ll)pwX_of_sum[i/g]*pwX_of_pwK[g]%MOD;
    			add(ans[i],(ll)F[g]*coef[g]%MOD);
    		}
    	}
    	while(T--){
    		cin>>n;
    		cout<<ans[n]<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    pandas 流式导出excel
    django serializer 定制error_message
    selenium etree xpath使用总结
    Python之路--Python基础
    初见Flask
    Git
    MySQL补充——索引,流程控制,数据备份,python操作mysql,SQLAlchemy
    Python之路--Django--Ajax、同源策略、Jsonp、CORS
    Python之路--Django--form组件与model form组件
    Python之路--Django--中间件
  • 原文地址:https://www.cnblogs.com/dysyn1314/p/13449847.html
Copyright © 2020-2023  润新知