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 }