【集训队互测2012】JZPKIL(伯努利数)(Pollard-Rho)(积性函数)

传送门


有了拉格朗日插值求自然数幂和,就算要好写也有差分法可以用,OI里面伯努利数还有什么用。

当数据范围不大,但是需要多次求出具体系数的时候,伯努利数就有用了。

O ( n 2 ) O(n^2) O(n2) 预处理组合数和 1 − n 1-n 1n 的逆元之后,利用伯努利数可以 O ( n ) O(n) O(n) 求出 n n n 次方幂和的多项式系数,这是拉格朗日插值和差分法不好做到的(当然也有可能是我菜)。

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

题解:

拿到式子先进行套路的化简:

A n s = ∑ i = 1 n ( i , n ) x [ i , n ] y = n y ∑ i = 1 n ( i , n ) x − y i y Ans=\sum_{i=1}^n(i,n)^x[i,n]^y=n^y\sum_{i=1}^n(i,n)^{x-y}i^y Ans=i=1n(i,n)x[i,n]y=nyi=1n(i,n)xyiy

前面的常数丢掉,考虑后面的:

∑ i = 1 n ( i , n ) x − y i y = ∑ d ∣ n d x − y ∑ i = 1 n / d [ ( i d , n ) = d ] ( i d ) y = ∑ d ∣ n d x ∑ i = 1 n / d i y [ ( i , n / d ) = 1 ] = ∑ d ∣ n d x ∑ t d ∣ n μ ( t ) t y ∑ i = 1 n / t d i y \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} ===i=1n(i,n)xyiydndxyi=1n/d[(id,n)=d](id)ydndxi=1n/diy[(i,n/d)=1]dndxtdnμ(t)tyi=1n/tdiy

设多项式 F k ( n ) = ∑ i = 1 n i k = ∑ i = 0 k + 1 c i n i F_k(n)=\sum\limits_{i=1}^ni^k=\sum\limits_{i=0}^{k+1}c_in^i Fk(n)=i=1nik=i=0k+1cini,其中 c i c_i ci 表示多项式的系数。

继续转化 ∑ i = 0 y + 1 c i ∑ d ∣ n d x ∑ t ∣ n d μ ( t ) t y ⋅ ( n t d ) 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} i=0y+1cidndxtdnμ(t)ty(tdn)i

不难发现后面是狄利克雷卷积的形式,函数为 i d x ∗ ( i d y ⋅ μ ) ∗ i d i id_x*(id_y\cdot \mu)*id_i idx(idyμ)idi

这是个积性函数,所以我们把多项式系数求出来,把 n n n 进行质因数分解,然后求质因子点值即可。

还剩的问题就是求质因子点值。

不难发现,由于中间有一个 μ \mu μ 所以中间的指数只需要考虑 0 , 1 0,1 0,1 就行了。

有点卡常,Pollard-Rho 需要优化,当然要是你用什么玄学分解也行。


代码:

#include
#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;}

你可能感兴趣的:(素数测试,分解质因数)