【集訓隊互測2012】JZPKIL(伯努利數)(Pollard-Rho)(積性函數)

傳送門


有了拉格朗日插值求自然數冪和,就算要好寫也有差分法可以用,OI裏面伯努利數還有什麼用。

當數據範圍不大,但是需要多次求出具體系數的時候,伯努利數就有用了。

O(n2)O(n^2) 預處理組合數和 1n1-n 的逆元之後,利用伯努利數可以 O(n)O(n) 求出 nn 次方冪和的多項式係數,這是拉格朗日插值和差分法不好做到的(當然也有可能是我菜)。

算了,不扯了,推出來就知道爲什麼拉格朗日插值和差分法不好做了。

題解:

拿到式子先進行套路的化簡:

Ans=i=1n(i,n)x[i,n]y=nyi=1n(i,n)xyiyAns=\sum_{i=1}^n(i,n)^x[i,n]^y=n^y\sum_{i=1}^n(i,n)^{x-y}i^y

前面的常數丟掉,考慮後面的:

i=1n(i,n)xyiy=dndxyi=1n/d[(id,n)=d](id)y=dndxi=1n/diy[(i,n/d)=1]=dndxtdnμ(t)tyi=1n/tdiy\begin{aligned} &\sum_{i=1}^n(i,n)^{x-y}i^y\\ =&\sum_{d\mid n}d^{x-y}\sum_{i=1}^{n/d}[(id,n)=d](id)^y\\ =&\sum_{d\mid n}d^x\sum_{i=1}^{n/d}i^y[(i,n/d)=1]\\ =&\sum_{d\mid n}d^x\sum_{td\mid n}\mu(t)t^y\sum_{i=1}^{n/td}i^y\\ \end{aligned}

設多項式 Fk(n)=i=1nik=i=0k+1ciniF_k(n)=\sum\limits_{i=1}^ni^k=\sum\limits_{i=0}^{k+1}c_in^i,其中 cic_i 表示多項式的係數。

繼續轉化 i=0y+1cidndxtndμ(t)ty(ntd)i \begin{aligned} \sum_{i=0}^{y+1}c_i\sum_{d\mid n}d^x\sum_{t\mid \frac{n}d}\mu(t)t^y\cdot (\frac{n}{td})^i \end{aligned}

不難發現後面是狄利克雷卷積的形式,函數爲 idx(idyμ)idiid_x*(id_y\cdot \mu)*id_i

這是個積性函數,所以我們把多項式係數求出來,把 nn 進行質因數分解,然後求質因子點值即可。

還剩的問題就是求質因子點值。

不難發現,由於中間有一個 μ\mu 所以中間的指數只需要考慮 0,10,1 就行了。

有點卡常,Pollard-Rho 需要優化,當然要是你用什麼玄學分解也行。


代碼:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

using std::cerr;
using std::cout;

cs int mod=1e9+7;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a-b<0?a-b+mod:a-b;}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;} 
inline void Mul(int &a,int b){a=mul(a,b);}
inline int po(int a,int b){
	int r=1;for(;b;b>>=1,Mul(a,a))if(b&1)Mul(r,a);return r;
}inline void ex_gcd(int a,int b,int &x,int &y){
	if(!b){x=1,y=0;return;}ex_gcd(b,a%b,y,x);y-=a/b*x;
}inline int Inv(int a){static int x,y;ex_gcd(mod,a,y,x);return x+(x>>31&mod);}
inline int MD(ll x){return x>=mod?x%mod:x;}


namespace Sieve{

cs int N=4e5+7;
int mrk[N],pr[N],pc;
void linear_sieves(int lim=1e4){
	for(int i=2;i<=lim;++i){
		if(!mrk[i])pr[++pc]=i;
		for(int re j=1;i*pr[j]<=lim;++j){
			mrk[i*pr[j]]=true;
			if(i%pr[j]==0)break;
		}
	}
}

std::mt19937 R(time(0));

inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} 
inline ll mul(ll a,ll b,ll mod){
	if(mod<2e9)return a*b%mod;
	return (a*b-(ll)((long double)a/mod*b)*mod+mod)%mod;
}inline ll power(ll a,ll b,ll mod){
	ll r=1;a%=mod;
	for(;b;b>>=1,a=mul(a,a,mod))
		if(b&1)r=mul(r,a,mod);
	return r;
}
static cs int p[17]=
		{2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59};
bool isprime(ll x){
	static std::uniform_int_distribution<int> rnd(0,16);
	ll t=x-1,s=0;while(!(t&1))t>>=1,++s;
	for(int re tim=0;tim<6;++tim){
		ll a=p[rnd(R)]%x;ll b=power(a,t,x);
		for(int re j=1;j<=s;++j){
			ll k=mul(b,b,x);
			if(k==1&&b!=1&&b!=x-1)return false;
			b=k;if(b==1)break;
		}if(b!=1)return false;
	}return true;
}

ll Rho(ll p){
	if(p%2==0)return 2;
	ll c=(ll)R()%(p-1)+2,x=1,m=1,t;
	for(int re k=2;;k<<=1){
		ll q=1;
		for(int re s=1;s<=k;++s){
			x=mul(x,x,p)+c;if(x>=p)x-=p;
			q=mul((x-m+p)%p,q,p);
			if(!(s&127)&&(t=gcd(p,q))!=1)return t;
		}if((t=gcd(p,q))!=1)return t;
		m=x;
	}assert(0);return -1;
}

}

ll pfc[100];int ord[100],pct;

void get_factor(ll x){
	using Sieve::isprime;using Sieve::Rho;if(x==1)return ;
	if(isprime(x)){pfc[++pct]=x;return;}
	ll p=x;while(p==x)p=Rho(p);ll g=std::__gcd(p,x/p);
	get_factor(p/g);get_factor(x/p/g);get_factor(g);
}

void factor(ll x){
	using Sieve::pc;using Sieve::pr;
	for(int re i=1;i<=pc;++i)
		if(x%pr[i]==0){
			pfc[++pct]=pr[i];
			while(x%pr[i]==0)
				x/=pr[i];
		}
	get_factor(x);
}

cs int N=3e3+7;

int fac[N],_fac[N],inv[N],B[N],coef[N];

inline int C(int n,int m){
	return n>=m&&m>=0?mul(fac[n],mul(_fac[m],_fac[n-m])):0; 
}

void calc_Poly(int y){
	coef[0]=0;
	for(int re i=0;i<=y;++i)
		coef[y+1-i]=mul(C(y+1,i),B[i]);
	for(int re i=0;i<=y+1;++i)
		Mul(coef[i],inv[y+1]);
	if(y)++coef[y];
}

ll n,nn;int x,y;
int G(int i,int p,int k){
	int res=0;
	for(int re q=0;q<=k;++q)
		Inc(res,po(p,((ll)q*x+(ll)(k-q)*i)%(mod-1)));
	for(int re q=0;q<k;++q)
		Dec(res,po(p,((ll)q*x+y+(ll)(k-q-1)*i)%(mod-1)));
	return res;
}

void Main(){
	Sieve::linear_sieves();
	fac[0]=fac[1]=1;
	inv[0]=inv[1]=1;_fac[0]=_fac[1]=1;
	for(int re i=2;i<N;++i){
		fac[i]=mul(fac[i-1],i);
		inv[i]=mul(inv[mod%i],mod-mod/i);
		_fac[i]=mul(_fac[i-1],inv[i]);
	}B[0]=1;
	for(int re i=1;i+1<N;++i){
		for(int re j=0;j<i;++j)
			Dec(B[i],mul(C(i+1,j),B[j]));
		Mul(B[i],inv[i+1]);
	}int T;scanf("%d",&T);
	while(T--){
		scanf("%lld%d%d",&n,&x,&y);
		nn=n;pct=0;factor(n);
		std::sort(pfc+1,pfc+pct+1);
		pct=std::unique(pfc+1,pfc+pct+1)-pfc-1;
		for(int re i=1;i<=pct;++i){
			ord[i]=0;
			while(n%pfc[i]==0)
				++ord[i],n/=pfc[i];
		}calc_Poly(y);int ans=0;
		for(int re i=0;i<=y+1;++i){
			int res=1;
			for(int re j=1;j<=pct;++j)
				Mul(res,G(i,pfc[j]%mod,ord[j]));
			Inc(ans,mul(res,coef[i]));
		}cout<<mul(ans,po(MD(nn),y))<<"\n";
	}
}

inline void file(){
#ifdef zxyoi
	freopen("jzpkil.in","r",stdin);
#endif
}signed main(){file();Main();return 0;}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章