• [ASDFZ]复活石


    Description

    给定\(f(i)\),求\(g(i)=\sum_{i_1|i}\sum_{i_2|i_1}\dots\sum_{i_k|i_{k-1}}f(i_k)(mod\;10^9+7)\).

    HINT

    \(n,k\leq10^5\)

    Solution

    30分

    \(f[i][j]\)表示选了\(i\)个数,积为\(j\)的总和.

    #include<cmath>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define K 10000
    #define N 100001
    #define T 300000
    #define M 1000000007
    using namespace std;
    typedef long long ll;
    int f[2][N],n,m,k;
    inline int read(){
    	int ret=0;char c=getchar();
    	while(!isdigit(c)) c=getchar();
    	while(isdigit(c)){ret=(ret<<1)+(ret<<3)+c-'0';c=getchar();}
    	return ret;
    }
    inline int rd(){
    	int ret=0ll;bool f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-') f=0;c=getchar();}
    	while(isdigit(c)){ret=(ret<<1)+(ret<<3)+c-'0';c=getchar();}
    	if(f) return ret;
    	return M-ret;
    }
    inline void Aireen(){
    	m=read();
    	while(m--){
    		n=read();k=read();
    		for(int i=1;i<=n;++i) f[0][i]=rd();
    		for(int i=1;i<=k;++i){
    			for(int j=1;j<=n;++j){
    				f[i&1][j]=0;
    				for(int l=sqrt(j);l;--l){
    					if(!(j%l)){
    						f[i&1][j]+=f[i&1^1][l];
    						if(f[i&1][j]>M) f[i&1][j]-=M;
    						if(l*l!=j) f[i&1][j]+=f[i&1^1][j/l];
    						if(f[i&1][j]>M) f[i&1][j]-=M;
    					}
    				}
    			}
    		}
    		for(int i=1;i<=n;++i)
    			printf("%d ",f[k&1][i]);
    		putchar('\n');
    	}
    }
    int main(){
    	freopen("b.in","r",stdin);
    	freopen("b.out","w",stdout);
    	Aireen();
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    } 
    

    100分

    inline void sieve(){
    	cnt=0;t[1]=1;
    	for(int i=1;i<=n;++i) g[i]=0;
    	for(int i=2;i<=n;++i){
    		if(!g[i]){
    			g[i]=i,p[++cnt]=i,t[i]=k;
    		}
    		for(int j=1,l,q,c,x;j<=cnt&&i*p[j]<=n;++j){
    			g[c=i*p[j]]=p[j];
    			if(mul[c]) t[c]=C(mul[c]+k-1,k-1); 
    			else{
    				q=c;t[c]=1;
    				while(q>1){
    					x=l=g[q];
    					while(true){
    						if(1ll*x*l>1ll*q||q%(x*l)) break;
    						x=x*l;
    					}
    					q/=x;
    					t[c]=1ll*t[c]*t[x]%M; 
    				}
    			}
    			if(!(i%p[j])) break;
    		}
    	}
    }
    

    相当于求每个数分解\(k\)次得到的可重\(i\)\(f(i)\)之和.
    实际上\(g(i)\)\(f(j)\;(i|j)\)之间的关系是只与\(k\)有关的.
    \(g(i)=t(\frac{i}{j})\times{f(j)}\).
    \(t(x)=\begin{cases}1&x=1\\k&x\;is\;prime\\C_{j+k-1}^{k-1}(隔板法)&x=p_i^j\\ \prod_{i=1}^{k}{t(p_k^{a_k})}&x=p_1^{a_1}\;\times\;p_2^{a_2}\;\times\dots\times\;p_k^{a_k}\\\end{cases}\)
    上面的式子很好理解,也很好证明,也就是运用了积性函数,隔板法,乘法原理的思想.
    至此,问题求解.

    #include<cmath>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define K 10000
    #define N 100001
    #define T 200001
    #define M 1000000007
    using namespace std;
    typedef long long ll;
    int f[N],g[N],p[K],t[N],mul[N],fac[T],rev[T],n,m,k,cnt,ans;
    inline int read(){
    	int ret=0;char c=getchar();
    	while(!isdigit(c)) c=getchar();
    	while(isdigit(c)){ret=(ret<<1)+(ret<<3)+c-'0';c=getchar();}
    	return ret;
    }
    inline int po(int x,int k){
    	int ret=1;
    	while(k){
    		if(k&1) ret=1ll*ret*x%M;
    		x=1ll*x*x%M;k>>=1;
    	}
    	return ret;
    }
    inline ll C(int n,int m){
    	return 1ll*fac[n]*rev[n-m]%M*rev[m]%M;
    }
    inline int chk(int k){
    	int l=g[k],ret=0;
    	while(k>1){
    		if(k%l) return 0;
    		k/=l;++ret;
    	}
    	return ret;
    }
    inline void prime(){
    	for(int i=2;i<N;++i){
    		if(!g[i]){
    			g[i]=i,p[++cnt]=i;
    		}
    		for(int j=1,l,q,c;j<=cnt&&i*p[j]<N;++j){
    			g[c=i*p[j]]=p[j];
    			if(!(i%p[j])) break;
    		}
    		mul[i]=chk(i);
    	}
    }
    inline void sieve(){
    	cnt=0;t[1]=1;
    	for(int i=1;i<=n;++i) g[i]=0;
    	for(int i=2;i<=n;++i){
    		if(!g[i]){
    			g[i]=i,p[++cnt]=i,t[i]=k;
    		}
    		for(int j=1,l,q,c,x;j<=cnt&&i*p[j]<=n;++j){
    			g[c=i*p[j]]=p[j];
    			if(mul[c]) t[c]=C(mul[c]+k-1,k-1); 
    			else{
    				q=c;t[c]=1;
    				while(q>1){
    					x=l=g[q];
    					while(true){
    						if(1ll*x*l>1ll*q||q%(x*l)) break;
    						x=x*l;
    					}
    					q/=x;
    					t[c]=1ll*t[c]*t[x]%M; 
    				}
    			}
    			if(!(i%p[j])) break;
    		}
    	}
    }
    inline void Aireen(){
    	fac[0]=fac[1]=1;
    	for(int i=2;i<T;++i)
    		fac[i]=1ll*fac[i-1]*i%M;
    	rev[T-1]=po(fac[T-1],M-2);
    	rev[0]=rev[1]=1;
    	for(int i=T-2;i>1;--i)
    		rev[i]=1ll*rev[i+1]*(i+1)%M;
    	prime();
    	m=read();
    	while(m--){
    		n=read();k=read();
    		for(int i=1;i<=n;++i) f[i]=read();
    		sieve();
    		for(int i=1;i<=n;++i) g[i]=0;
    		for(int i=1;i<=n;++i)
    			for(int j=i;j<=n;j+=i){
    				g[j]+=1ll*t[j/i]*f[i]%M;
    				if(g[j]>M) g[j]-=M;
    			}
    		for(int i=1;i<=n;++i)
    			printf("%d ",g[i]);
    		putchar('\n');
    	}
    }
    int main(){
    	freopen("b.in","r",stdin);
    	freopen("b.out","w",stdout);
    	Aireen();
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    } 
    

    2017-04-05 22:54:41

  • 相关阅读:
    函数和递归
    对象
    数组
    For...In 声明
    JavaScript 变量的生存期
    Hadoop Hive与Hbase整合+thrift
    朱子治家格言
    大学
    《孙子兵法》【谋攻第三】
    棋经十三篇
  • 原文地址:https://www.cnblogs.com/AireenYe/p/15609376.html
Copyright © 2020-2023  润新知