题意:在一个
你的任务是求出所有可能的生成树的价值之和,对
数据范围与约定:
对于
对于
对于
对于
对于
对于
保证数据存在梯度。
解析:一道很难的题,首先一看模数就知道这题应该是道多项式题。
我们把每个连通块看作一个点,那么要统计所有可能的生成树的价值之和,主要有如下几个因素决定:
- 生成树的种类不同,也即连通块的度数不同;
- 由同一连通块连出的边的起点不同;
- 价值式子。
对于第一个因素,我们用 prufer 序列来对应树,设
那么对于一个确定的
对于一个已经确定的
对于第二个因素,一个连通块的度数已经确定为
第三个因素直接套用式子即可。把这三个因素乘起来,即是对于一个确定的
接下来我们尝试化简这个式子:
上面这步化简主要运用了积式的结合律,即
上面首先运用了和式的分配律,即
因此我们的答案式子即为:
发现
后面这个和式是对所有满足
设上面这个和式以
上面对于后面
我们把每一项的
求数列幂和
我们设
转换成封闭形式后出现了
因此,我们只要求出
现在研究如何快速求出
对于
然后这道题就解决了。
/*
* @Author: clorf
* @Date: 2021-02-16 20:42:39
* @Last Modified by: clorf
* @Last Modified time: 2021-02-16 20:46:21
*/
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctime>
#include<cctype>
#define INF 2e9
#define rg register
using namespace std;
const int G=3;
const int mod=998244353;
const int maxn=30000;
const long double Pi=acos(-1.0);
const double eps=1e-7;
//1.数组开小
//2.没用long long/爆了类型存储范围
//3.写之前式子没推清楚
//4.变量写错(想当然typo/没想清楚含义)
//5.写之前没想清楚复杂度
//6.常量数字与long long连用时要加ll!!!
//7.考虑无解和多解的情况
//8.两个int连成爆long long的一定要加1ll!!!!
//9.先除后乘!!!!!!
template<class T>void read(T &x)
{
x=0;int f=0;char ch=getchar();
while(!isdigit(ch)){f|=(ch=='-');ch=getchar();}
while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x=f?-x:x;
return;
}
int n,m,invG,a[maxn*3+5],b[maxn*3+5],c[maxn*3+5];
int rev[maxn*3+5],h[maxn*3+5],p[maxn*3+5];
int df[maxn*3+5],q[maxn*3+5],fac[maxn+5];
int res[30][maxn*3+5],invf[maxn+5],d[maxn*3+5],e[maxn*3+5];
inline int inc(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 power(int a,int b,int p)
{
int ans=1;
for(;b;b>>=1)
{
if(b&1)
ans=1ll*ans*a%p;
a=1ll*a*a%p;
}
return ans;
}
inline int inv(int x)
{
return power(x,mod-2,mod);
}
inline int ready(int len)
{
int maxx=1,num=0;
while(maxx<len)
{
maxx<<=1;
num++;
}
for(int i=0;i<=maxx;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(num-1));
return maxx;
}
inline void NTT(int *a,int maxx,int type)
{
for(int i=0;i<maxx;i++)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(int mid=1;mid<maxx;mid<<=1)
{
int w1=power(~type?G:invG,(mod-1)/(mid<<1),mod);
for(int r=mid<<1,j=0;j<maxx;j+=r)
{
int w=1;
for(int k=0;k<mid;k++,w=1ll*w*w1%mod)
{
int x=a[j|k];
int y=1ll*w*a[j|k|mid]%mod;
a[j|k]=inc(x,y);
a[j|k|mid]=dec(x,y);
}
}
}
if(!(~type))
{
int invm=inv(maxx);
for(int i=0;i<maxx;i++)
a[i]=1ll*a[i]*invm%mod;
}
}
inline void polyinv(int *f,int *g,int n)
{
if(n==1)
{
g[0]=inv(f[0]);
return ;
}
polyinv(f,g,(n+1)>>1);
int maxx=ready(n<<1);
for(int i=0;i<n;i++)
h[i]=f[i];
for(int i=n;i<maxx;i++)
h[i]=0;
NTT(h,maxx,1);
NTT(g,maxx,1);
for(int i=0;i<maxx;i++)
h[i]=1ll*h[i]*g[i]%mod;
for(int i=0;i<maxx;i++)
g[i]=1ll*g[i]*dec(2ll,h[i])%mod;
NTT(g,maxx,-1);
for(int i=n;i<maxx;i++)
g[i]=0;
}
inline void polyderi(int *f,int *g,int n)
{
for(int i=1;i<n;i++)
g[i-1]=1ll*f[i]*i%mod;
g[n-1]=0;
}
inline void polyinte(int *f,int *g,int n)
{
for(int i=1;i<n;i++)
g[i]=1ll*f[i-1]*inv(i)%mod;
g[0]=0;
}
inline void polyln(int *f,int *g,int n)
{
int maxx=ready(n<<1);
for(int i=0;i<maxx;i++)
df[i]=p[i]=0;
polyderi(f,df,n);
polyinv(f,p,n);
NTT(p,maxx,1);
NTT(df,maxx,1);
for(int i=0;i<maxx;i++)
p[i]=1ll*p[i]*df[i]%mod;
NTT(p,maxx,-1);
for(int i=n;i<maxx;i++)
p[i]=0;
polyinte(p,g,n);
}
inline void polyexp(int *f,int *g,int n)
{
if(n==1)
{
g[0]=1;
return ;
}
polyexp(f,g,(n+1)>>1);
int maxx=ready(n<<1);
polyln(g,q,n);
for(int i=0;i<n;i++)
q[i]=dec(f[i],q[i]);
q[0]=inc(q[0],1ll);
NTT(q,maxx,1);
NTT(g,maxx,1);
for(int i=0;i<maxx;i++)
g[i]=1ll*g[i]*q[i]%mod;
NTT(g,maxx,-1);
for(int i=n;i<maxx;i++)
g[i]=q[i]=0;
}
inline void polycumprod(int *f,int l,int r,int op)
{
if(l==r)
{
res[op][0]=1;
res[op][1]=mod-f[l];
return ;
}
int mid=(l+r)>>1;
polycumprod(f,l,mid,op);
polycumprod(f,mid+1,r,op+1);
int maxx=ready(r-l+2);
for(int i=mid-l+2;i<maxx;i++)
res[op][i]=0;
for(int i=r-mid+1;i<maxx;i++)
res[op+1][i]=0;
NTT(res[op],maxx,1);
NTT(res[op+1],maxx,1);
for(int i=0;i<maxx;i++)
res[op][i]=1ll*res[op][i]*res[op+1][i]%mod;
NTT(res[op],maxx,-1);
}
int main()
{
invG=inv(G);
scanf("%d%d",&n,&m);
int num=1;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
num=1ll*num*a[i]%mod;
}
polycumprod(a,1,n+1,0);
polyln(res[0],b,n+1);
polyderi(b,c,n+1);
for(int i=0;i<n;i++)
if(c[i])
c[i]=mod-c[i];
for(int i=n-1;i>=1;i--)
c[i]=c[i-1];
c[0]=n;
fac[0]=invf[0]=1;
for(int i=1;i<n;i++)
fac[i]=1ll*fac[i-1]*i%mod;
invf[n-1]=inv(fac[n-1]);
for(int i=n-2;i>=1;i--)
invf[i]=1ll*invf[i+1]*(i+1)%mod;
for(int i=0;i<n;i++)
{
int t=power(i+1,m,mod);
b[i]=1ll*t*invf[i]%mod;
a[i]=1ll*b[i]*t%mod;
}
polyln(b,d,n);
polyinv(b,e,n);
int maxx=ready(n<<1);
NTT(a,maxx,1);
NTT(e,maxx,1);
for(int i=0;i<maxx;i++)
a[i]=1ll*a[i]*e[i]%mod;
NTT(a,maxx,-1);
for(int i=n;i<maxx;i++)
a[i]=0;
for(int i=0;i<n;i++)
{
a[i]=1ll*a[i]*c[i]%mod;
d[i]=1ll*d[i]*c[i]%mod;
c[i]=0;
}
polyexp(d,c,n);
NTT(c,maxx,1);
NTT(a,maxx,1);
for(int i=0;i<maxx;i++)
a[i]=1ll*a[i]*c[i]%mod;
NTT(a,maxx,-1);
printf("%d",1ll*a[n-2]*fac[n-2]%mod*num%mod);
return 0;
}

