Link
看到全是度数相关的计数就可以考虑Prüfer序列。
一个点的度数就是其在Prüfer序列中的出现次数(+1),而一个Prüfer序列的贡献就是其所有元素出现次数(+1)的乘积,我们可以把乘积拆开dp。
设(f_{x,i})表示考虑前(x)个点,Prüfer序列长度为(i)的答案之和。
边界就是(f_{0,0}=1),答案就是(f_{n,n+2})。
转移非常显然,枚举(x)的出现次数得到(f_{x,i}=sumlimits_{j=0}^i{ichoose j}(j+1)^Kf_{x-1,i-j})。
显然这是个卷积的形式:(frac{f_{x,k}}{k!}=sumlimits_{i+j=k}frac{(i+1)^K}{i!}frac{f_{x-1,j}}{j!})。
设(P(x)=sumlimits_{i=0}^{n-2}frac{(i+1)^K}{i!}x^i),那么答案就是(frac{[x^{n-2}]P(x)^n(n-2)!}{n^{n-2}}),可以倍增快速幂解决。
然后考虑(K=1)的特殊情况,此时(P(x)=sumlimits_{i=0}^{n-2}frac{i+1}{i!}x^i=(x+1)e^x),因此(P(x)^n=(x+1)^ne^{nx}=(sumlimits_{i=0}^n{nchoose i}x^i)(sumlimits_{i=0}^nfrac{n^i}{i!}x^i)),([x^{n-2}]P(x)^n=sumlimits_{i=0}^{n-2}{nchoose i+2}frac{n^i}{i!}),直接(O(n))计算即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
const int N=2000007,M=262145,P=998244353;
int read(){int x;scanf("%d",&x);return x;}
int inc(int a,int b){return a+=b-P,a+(a>>31&P);}
int dec(int a,int b){return a-=b,a+(a>>31&P);}
int mul(int a,int b){return 1ll*a*b%P;}
int pow(int a,int k=P-2){int r=1;for(;k;k>>=1,a=mul(a,a))if(k&1)r=mul(a,r);return r;}
int n,k,lim,fac[N],ifac[N],rev[M],w[M],E[M],I[M];
void init()
{
fac[0]=1;
for(int i=1;i<=2000000;++i) fac[i]=mul(fac[i-1],i);
ifac[2000000]=pow(fac[2000000]);
for(int i=2000000;i;--i) ifac[i-1]=mul(ifac[i],i);
}
void init(int n)
{
lim=1<<(32-__builtin_clz(n)),w[lim>>1]=1;int g=pow(3,P/lim);
for(int i=1;i<lim;++i) rev[i]=(rev[i>>1]>>1)|(i&1? lim>>1:0);
w[lim>>1]=1;
for(int i=(lim>>1)+1;i<lim;++i) w[i]=mul(w[i-1],g);
for(int i=(lim>>1)-1;i;--i) w[i]=w[i<<1];
}
void NTT(int*a,int f)
{
if(!~f) std::reverse(a+1,a+lim);
for(int i=0;i<lim;++i) if(i<rev[i]) std::swap(a[i],a[rev[i]]);
for(int i=1;i<lim;i<<=1) for(int j=0,l=i<<1;j<lim;j+=l) for(int k=0,x;k<i;++k) x=mul(a[i+j+k],w[i+k]),a[i+j+k]=dec(a[j+k],x),a[j+k]=inc(a[j+k],x);
if(!~f) for(int i=0,x=P-P/lim;i<lim;++i) a[i]=mul(a[i],x);
}
void solve1()
{
int ans=0;
for(int i=0,t=1;i<=n-2;++i) ans=inc(ans,1ll*fac[n]*ifac[i+2]%P*ifac[n-i-2]%P*t%P*ifac[i]%P),t=mul(t,n);
printf("%d
",mul(mul(ans,fac[n-2]),pow(pow(n,n-2))));
}
void solve2()
{
init(2*n-4),memset(E+n-1,0,(lim-n+4)<<2);
for(int i=0;i<=n-2;++i) E[i]=mul(pow(i+1,k),ifac[i]);
NTT(E,1),std::fill(I,I+lim,1);
for(int t=n;t;t>>=1)
{
if(t&1)
{
for(int i=0;i<lim;++i) I[i]=mul(I[i],E[i]);
NTT(I,-1),memset(I+n-1,0,(n-2)<<2),NTT(I,1);
}
for(int i=0;i<lim;++i) E[i]=mul(E[i],E[i]);
NTT(E,-1),memset(E+n-1,0,(n-2)<<2),NTT(E,1);
}
NTT(I,-1),printf("%d
",mul(mul(I[n-2],fac[n-2]),pow(pow(n,n-2))));
}
int main(){init();for(int T=read();T;--T) n=read(),k=read(),k==1? solve1():solve2();}