题解:
岛屿之间的边砍/不砍情况有$2^n$种,
但是需要剪掉所有的岛上都首尾相连的情况。
$dp$一下对于完全图没有限制($f$)/有限制($g$)的情况数。
方程:$$f[i]=sum(C(i-1,j-1)*j^{(j-2)}*f[i-j])$$
$$g[i]=sum(C(i-2,j-2)*j^{(j-2)}*f[i-j])$$
其中$j^(j-2)$是$j$个点的完全图的生成树个数。
打开组合数之后$CDQ$即可。
统计答案时$ans=2^n*prod(f)-prod(g)$。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MOD = 998244353; const int N = 150000; typedef long long ll; template<typename T> inline void read(T&x) { T f = 1,c = 0;char ch = getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();} x = f * c; } ll fastpow(ll x,int y) { ll ret = 1; while(y) { if(y&1)ret= ret*x%MOD; x= x*x % MOD; y>>=1; } return ret; } int to[4*N],lim=1,L; ll W[4*N],inv; void ntt(ll *a,int len,int k) { for(int i=0;i<len;i++) if(i<to[i])swap(a[i],a[to[i]]); for(int i=1;i<len;i<<=1) { ll w0 = W[i]; for(int j=0;j<len;j+=(i<<1)) { ll w = 1; for(int o=0;o<i;o++,w=w*w0%MOD) { ll w1 = a[j+o],w2 = a[j+o+i]*w%MOD; a[j+o] = (w1+w2)%MOD; a[j+o+i] = (w1-w2+MOD)%MOD; } } } if(k==-1) { for(int i=1;i<(len>>1);i++)swap(a[i],a[len-i]); for(int i=0;i<len;i++)a[i]=a[i]*inv%MOD; } } ll a[4*N],b[4*N],c[4*N],d[4*N],e[4*N]; ll f[N],g[N],fj[N],gj[N],jc[N],jn[N]; void clear() { for(int i=0;i<lim;i++)a[i]=b[i]=0; } void work() { ntt(a,lim,1),ntt(b,lim,1),ntt(c,lim,1); for(int i=0;i<lim;i++)d[i]=a[i]*b[i]%MOD,e[i]=a[i]*c[i]%MOD; ntt(d,lim,-1),ntt(e,lim,-1); } void cdq(int l,int r) { if(l==r) { if(l==0)f[l] = 1; else f[l] = f[l]*jc[l-1]%MOD; if(l<=1)g[l] = 1; else g[l] = g[l]*jc[l-2]%MOD; return ; } int mid = (l+r)>>1; cdq(l,mid); lim = 1,L = 0; while(lim<=(r-l+1))lim<<=1,L++; for(int i=1;i<lim;i++)to[i]=((to[i>>1]>>1)|((i&1)<<(L-1))); inv = fastpow(lim,MOD-2); for(int i=1;i<lim;i<<=1)W[i]=fastpow(3,(MOD-1)/(i<<1)); clear(); for(int i=0;i<=mid-l;i++)a[i]=f[i+l]*jn[i+l]%MOD; for(int i=0;i<=r-l;i++)b[i]=fj[i],c[i]=gj[i]; work(); for(int i=mid-l+1;i<=r-l;i++)f[i+l]=(f[i+l]+d[i])%MOD; for(int i=mid-l+1;i<=r-l;i++)g[i+l]=(g[i+l]+e[i])%MOD; cdq(mid+1,r); } int T,n,x; int main() { jc[0]=jn[0]=1; fj[1]=jc[1]=jn[1]=1; for(int i=2;i<=100000;i++) { jc[i] = jc[i-1] * i % MOD; jn[i] = fastpow(jc[i],MOD-2); ll tmp = fastpow(i,i-2); fj[i] = tmp*jn[i-1]%MOD; gj[i] = tmp*jn[i-2]%MOD; } cdq(0,100000); read(T); while(T--) { read(n); ll s1=1,s2=1; for(int i=1;i<=n;i++) { read(x); s1 = s1 * f[x]%MOD; s2 = s2 * g[x]%MOD; } s1 = s1*fastpow(2,n)%MOD; printf("%lld ",(s1-s2+MOD)%MOD); } return 0; }