【JZOJ5034】B 题解

题目

  $k \leq n \leq 50$,方案数 $\bmod 998244353$

题解

  这个题很妙。。。

  我们知道矩阵树定理,即基尔霍夫矩阵的任意一个 $n-1$ 阶主子式就是生成树个数。
  现在加了个限制,即原图的边最多不选 $k$ 个,怎么做呢?

  其实就是要把原图边和非原图边用不同的方法表示。
  比如用 $x$ 表示一条原图边,用 $1$ 表示非原图边。这里的 $x$ 是多项式的一次未知数的意思。
  比如有个点连了 $3$ 条原图边、$2$ 条非原图边,那么它的度数就是 $3x+2$。相应地,邻接矩阵里也是用 $x$ 和 $1$ 来表示。
  那么此时的主子式就是一个多项式,其中 $x^i$ 的系数就表示保留 $i$ 条原图边的方案数。

  现在的问题是如何把这个多项式求出来。可以用插值法的思想,给 $x$ 代入 $n$ 个不同的值,最后再插值求多项式。可以用拉格朗日插值法什么的。我用的是 DFT。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

typedef long long LL;

const int maxn=55, maxlen=150;
const LL mo=998244353;

int n,K,len;
bool mp[maxn][maxn];
LL G0[maxn][maxn][2];

LL mi(LL x,LL y)
{
LL re=1;
for(; y; y>>=1, x=x*x%mo) if (y&1) re=re*x%mo;
return re;
}

LL G[maxn][maxn],w[maxlen];
LL Determinant(int n)
{
LL d=1;
fo(i,0,n)
{
fo(j,i,n) if (G[j][i]>0)
{
swap(G[i],G[j]);
if (j!=i) d*=-1;
break;
}
fo(j,i+1,n)
{
LL c=(-G[j][i]*mi(G[i][i],mo-2)%mo+mo)%mo;
fo(k,0,n) G[j][k]=(G[j][k]+c*G[i][k])%mo;
}
}
fo(i,0,n) d=d*G[i][i]%mo;
return (d%mo+mo)%mo;
}

LL y[maxlen];
int main()
{
scanf("%d %d",&n,&K);
K=n-1-K;
if (n==1) {printf("1\n"); return 0;}
for(len=1; len<n; len<<=1);
fo(i,1,n-1)
{
int x;
scanf("%d",&x);
G0[x][x][1]++, G0[i][i][1]++;
G0[x][i][1]--, G0[i][x][1]--;
mp[x][i]=mp[i][x]=1;
}
fo(i,0,n-2)
fo(j,i+1,n-1) if (!mp[i][j])
{
G0[i][i][0]++, G0[j][j][0]++;
G0[i][j][0]--, G0[j][i][0]--;
}

w[0]=1;
w[1]=mi(3,(mo-1)/len);
fo(i,2,len) w[i]=(w[i-1]*w[1])%mo;

fo(wi,0,len-1)
{
fo(i,0,n-1)
fo(j,0,n-1) G[i][j]=((G0[i][j][0]+G0[i][j][1]*w[wi])%mo+mo)%mo;
y[wi]=Determinant(n-2);
}

LL ans=0;
fo(i,K,len-1)
fo(j,0,len-1) ans=(ans+y[j]*mi(w[len-i],j))%mo;

printf("%lld\n",ans*mi(len,mo-2)%mo);
}