zoukankan      html  css  js  c++  java
  • 【GDKOI2016】小学生数学题 【自然数幂求和】【斯特林数】

    题意:求(sum_{i=1}^ni^{-1} mod p^k)的值。保证(p)为质数,(n imes p^k≤10^{18})
    题解:神题!细节巨多!
    (f(n,k)=sum_{i=1}^{n}i^{-1} mod p^k)(g(n,k)=sum_{i=1,i eq jp}^{n}i^{-1} mod p^k)
    (f(n,k)=g(n,k)+frac{f(lfloorfrac{n}{p} floor,k+1)}{p})
    为什么后面那里是k+1呢?
    因为若(a≡b mod c),则(ak≡bk mod ck)
    我们把那一部分先整体乘(p),最后再除回来就好。
    这样我们就可以递归计算了。
    如何求g(n,k)?
    (g(n,k))
    (=sum_{i=a+bp<=n}frac{1}{i})
    (=sum_{a=1}^{p-1}sum_{b=0}^{lfloorfrac{n-a}{p} floor}frac{1}{a+bp})
    (=sum_{a=1}^{p-1}sum_{b=0}^{lfloorfrac{n-a}{p} floor}(a+bp)^{-1})
    这个东西用广义二项式定理展开一下
    ((a+bp)^{-1}=sum_{i=0}^{infty}C_{-1}^{i}a^{-1-i}b^ip^i=sum_{i=0}^{infty}(-1)^ia^{-1-i}b^ip^i)
    又因为我们模了一个(p^k)
    所以
    ((a+bp)^{-1}=sum_{i=0}^{k-1}(-1)^ia^{-1-i}b^ip^i)
    所以
    (g(n,k))
    (=sum_{i=0}^{k-1}(-p)^isum_{a=1}^{p-1}frac{1}{a^{i+1}}sum_{b=0}^{lfloorfrac{n-a}{p} floor}b^i)
    我们令(S_k(n))表示(sum_{i=0}^{n}i^k)
    (g(n,k)=sum_{i=0}^{k-1}(-p)^isum_{a=1}^{p-1}frac{1}{a^{i+1}}S_i(lfloorfrac{n-a}{p} floor))
    如何求(S_k(n)?)
    我们先证一个东西:
    (x^{overline n}=Pi_{i=x}^{x+n-1}i=sum_{k}s(n,k)x^k),s是第一类斯特林数。
    可以转化为证([x^p]x^{overline n}=[x^p]sum_{k}s(n,k)x^{k}=s(n,p))
    显然在(n=1)的情况下是成立的。
    ([x^k]x^{overline n})
    (=[x^k](x+n-1)x^{overline{n-1}})
    (=[x^k](x+n-1)x^{overline{n-1}})
    (=[x^k]x imes x^{overline{n-1}}+[x^k](n-1)x^{overline{n-1}})
    (=[x^{k-1}]x^{overline{n-1}}+[x^k](n-1)x^{overline{n-1}})
    (=s(n-1,k-1)+(n-1)s(n-1,k))
    (=s(n,k))
    证明完毕。
    我们再证一个东西:

    [x^n=n!C_{x}^{n}-sum_{j=1}^{n-1}s(n,j)x^j ]

    其实挺显然的,上面那个证明的式子(x^n)的项系数为1,所以一减就可以得到这个式子。
    我们还要证一个东西:

    [sum_{i=k}^nC_{i}^{k}=C_{n+1}^{k+1} ]

    怎么证?

    [sum_{i=k}^nC_{i}^{k}=sum_{i=k}^{n-1}C_{i}^{k}+C_{n}^{k}\=C_{n}^{k}+C_{n}^{k+1}\=C_{n+1}^{k+1} ]

    证明完毕。
    终于要继续自然数幂求和啦!有了之前推的一堆式子,我们就可以化简式子了。
    (S_{k}(n))
    (=sum_{i=0}^{n}i^k)
    (=sum_{i=0}^{n}k!C_{i}^{k}-sum_{j=1}^{k-1}s(k,j)i^j)
    (=k!(sum_{i=0}^{n}C_{i}^{k})-sum_{i=0}^{n}sum_{j=1}^{k-1}s(k,j)i^j)
    (=k!C_{n+1}^{k+1}sum_{j=1}^{k-1}s(k,j)sum_{i=0}^{n}i^j)
    对于固定的(n),这个可以(O(k^2))预处理出来。然后代会这个式子里计算。
    (g(n,k)=sum_{i=0}^{k-1}(-p)^isum_{a=1}^{p-1}frac{1}{a^{i+1}}S_i(lfloorfrac{n-a}{p} floor))
    对于一些零碎的部分,我是直接暴力计算的。
    这一题数域可能很大,我写了(O(1))快速乘法。
    这题好难写啊!QAQ
    代码

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define int long long
    using namespace std;
    int p,k,n,x,y,r[100005],s[105][105];
    int mul(int a,int b,int mod){
    	int c=a*(double)b/mod+0.5;
    	int res=a*b-c*mod;
    	if(res<0){
    		res+=mod;
    	}
    	return res;
    }
    int fastpow(int a,int x,int mod){
    	a%=mod;
    	int res=1;
    	while(x){
    		if(x&1){
    			res=mul(res,a,mod);
    		}
    		x>>=1;
    		a=mul(a,a,mod);
    	}
    	return res;
    }
    int exgcd(int a,int b,int &x,int &y){
    	if(!b){
    		x=1;
    		y=0;
    		return a;
    	}
    	int d=exgcd(b,a%b,y,x);
    	y-=a/b*x;
    	return d;
    }
    int getinv(int a,int b){
    	exgcd(a,b,x,y);
    	return (x%b+b)%b;
    }
    void init(int n,int k){
    	const int mod=pow(p,k);
    	r[0]=n+1;
    	s[0][0]=1;
    	for(int i=1;i<=k;i++){
    		for(int j=1;j<=k;j++){
    			s[i][j]=(s[i-1][j-1]+mul(s[i-1][j],i-1,mod))%mod;
    		}
    	}
    	for(int i=1;i<=k;i++){
    		for(int j=1;j<=i;j++){
    			if((i+j)&1){
    				s[i][j]=mod-s[i][j];
    			}
    		}
    	}
    	for(int i=1;i<=k;i++){
    		r[i]=1;
    		bool flag=false;
    		for(int j=n+1;j>=n-i+1;j--){
    			if(!flag&&j%(i+1)==0){
    				flag=true;
    				r[i]=mul(r[i],j/(i+1),mod);
    			}else{
    				r[i]=mul(r[i],j,mod);
    			}
    		}
    		if(!flag){
    			r[i]=mul(r[i],getinv(i+1,mod),mod);
    		}
    		for(int j=1;j<i;j++){
    			r[i]=(r[i]-mul(s[i][j],r[j],mod)+mod)%mod;
    		}
    	}
    	return;
    }
    int g(int n,int k){
    	const int mod=pow(p,k);
    	int rem=n%p,res=0;
    	for(int i=n-rem+1;i<=n;i++){
    		res=(res+getinv(i,mod))%mod;
    	}
    	n-=rem;
    	if(!n){
    		return res;
    	}
    	init((n-1)/p,k);
    	for(int i=0,base=1;i<k;i++,base=(base*(-p)%mod+mod)%mod){
    		for(int j=1;j<p;j++){
    			res=(res+mul(mul(base,getinv(fastpow(j,i+1,mod),mod),mod),r[i],mod))%mod;
    		}
    	}
    	return res;
    }
    int f(int n,int k){
    	if(!n){
    		return 0;
    	}
    	return (g(n,k)+f(n/p,k+1)/p)%(int)(pow(p,k));
    }
    signed main(){
    	scanf("%lld%lld%lld",&p,&k,&n);
    	printf("%lld
    ",f(n,k));
    	return 0;
    }
    
  • 相关阅读:
    JAVA Oauth 认证服务器的搭建
    ibatis 中isNull, isNotNull与isEmpty, isNotEmpty区别
    Java OAuth开发包资料
    hOAuth2.0认证和授权原理
    Spring+Quartz实现定时任务的配置方法
    cron表达式详解(Spring定时任务配置时间间隔)
    spring定时任务的配置使用
    [spring-framework]Spring定时器的配置和使用
    net.sf.json在处理json对象转换为普通java实体对象时的问题和解决方案
    大数据和拉普拉斯妖
  • 原文地址:https://www.cnblogs.com/2016gdgzoi471/p/9477045.html
Copyright © 2011-2022 走看看