有了拉格朗日插值求自然数幂和,就算要好写也有差分法可以用,OI里面伯努利数还有什么用。
当数据范围不大,但是需要多次求出具体系数的时候,伯努利数就有用了。
在 O ( n 2 ) O(n^2) O(n2) 预处理组合数和 1 − n 1-n 1−n 的逆元之后,利用伯努利数可以 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=1∑n(i,n)x[i,n]y=nyi=1∑n(i,n)x−yiy
前面的常数丢掉,考虑后面的:
∑ 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=1∑n(i,n)x−yiyd∣n∑dx−yi=1∑n/d[(id,n)=d](id)yd∣n∑dxi=1∑n/diy[(i,n/d)=1]d∣n∑dxtd∣n∑μ(t)tyi=1∑n/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=1∑nik=i=0∑k+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=0∑y+1cid∣n∑dxt∣dn∑μ(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;}