codeforces 917D Stranger Trees

题目链接

 

正解:矩阵树定理+拉格朗日插值。

一下午就搞了这一道题,看鬼畜英文题解看了好久。。

首先这题出题人给了两种做法,感觉容斥+$prufer$序列+$dp$的做法细节有点多所以没看,然而这个做法似乎更难想。。

我们先构造一个函数$f(x)$,表示用一个完全图和$x-1$棵原树的边,构成的生成树的方案数。

也就是说,原树的每条边复制成$x$条,不在原树的边都变成一条边,求这个图的生成树的方案数。

然后我们可以发现,这个方案数实际上就等于$\sum_{i=0}^{n-1}x^{i}*ans_{i}$,其中$ans_{i}$表示询问的恰好有$i$条边的答案。

稍微解释一下,我们选定了原树的$i$条边,那么原树这$i$条边每条边就有$x$种选择,其他边只有$1$种选择。

然后现在我们的目标就变成了求出这个函数所表示的多项式的系数。

那么我们可以算出$x$取$[1,n]$的答案,用拉格朗日插值求出多项式,计算答案可以用矩阵树定理。

复杂度为$O(n^{4}+n^{3})$,写完题解以后发现也不是很难。。

 

 1 #include <bits/stdc++.h>
 2 #define il inline
 3 #define RG register
 4 #define ll long long
 5 #define rhl (1000000007)
 6 #define N (105)
 7 
 8 using namespace std;
 9 
10 int a[N][N],g[N][N],p[N],ans[N],fac[N],ifac[N],inv[N],n,len;
11 
12 il int gi(){
13   RG int x=0,q=1; RG char ch=getchar();
14   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
15   if (ch=='-') q=-1,ch=getchar();
16   while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
17   return q*x;
18 }
19 
20 il int qpow(RG int a,RG int b){
21   RG int ans=1;
22   while (b){
23     if (b&1) ans=1LL*ans*a%rhl;
24     if (b>>=1) a=1LL*a*a%rhl;
25   }
26   return ans;
27 }
28 
29 il int gauss(){
30   RG int res=1;
31   for (RG int i=1,id,inv;i<n;++i){
32     for (id=i;id<n && !a[id][i];++id); if (id>=n) return 0;
33     if (id!=i){
34       for (RG int j=1;j<n;++j) swap(a[i][j],a[id][j]);
35       res=-res;
36     }
37     res=1LL*res*a[i][i]%rhl,inv=qpow(a[i][i],rhl-2);
38     for (RG int j=i+1,tmp;j<n;++j){
39       if (!a[j][i]) continue;
40       tmp=1LL*a[j][i]*inv%rhl;
41       for (RG int k=i;k<n;++k)
42     a[j][k]=(a[j][k]-1LL*a[i][k]*tmp)%rhl;
43     }
44   }
45   return (res+rhl)%rhl;
46 }
47 
48 int main(){
49 #ifndef ONLINE_JUDGE
50   freopen("stranger.in","r",stdin);
51   freopen("stranger.out","w",stdout);
52 #endif
53   n=gi(),fac[0]=ifac[0]=1;
54   for (RG int i=1;i<=n;++i){
55     inv[i]=i==1?1:1LL*(rhl-rhl/i)*inv[rhl%i]%rhl;
56     fac[i]=1LL*fac[i-1]*i%rhl;
57     ifac[i]=1LL*ifac[i-1]*inv[i]%rhl;
58   }
59   for (RG int i=1,u,v;i<n;++i)
60     u=gi(),v=gi(),g[u][v]=g[v][u]=1;
61   for (RG int k=1;k<=n;++k){
62     for (RG int i=1;i<=n;++i)
63       for (RG int j=1;j<=n;++j) a[i][j]=0;
64     for (RG int i=1;i<n;++i)
65       for (RG int j=i+1,tmp;j<=n;++j){
66     tmp=g[i][j] ? k : 1;
67     a[i][j]-=tmp,a[j][i]-=tmp;
68     a[i][i]+=tmp,a[j][j]+=tmp;
69       }
70     p[len=0]=1LL*gauss()*ifac[k-1]%rhl*ifac[n-k]%rhl;
71     if ((n-k)&1) p[0]=rhl-p[0];
72     for (RG int t=1,tmp;t<=n;++t){
73       if (k==t) continue; tmp=rhl-t;
74       for (RG int i=++len;~i;--i)
75     p[i]=(1LL*tmp*p[i]+(i?p[i-1]:0))%rhl;
76     }
77     for (RG int i=0;i<=len;++i){
78       ans[i]+=p[i],p[i]=0; if (ans[i]>=rhl) ans[i]-=rhl;
79     }
80   }
81   for (RG int i=0;i<n;++i) printf("%d ",ans[i]); return 0;
82 }

 

posted @ 2018-02-25 17:29  wfj_2048  阅读(483)  评论(2编辑  收藏  举报