1. 程式人生 > >【XSY1537】五顏六色的幻想鄉(矩陣樹定理+高斯消元+拉格朗日插值)

【XSY1537】五顏六色的幻想鄉(矩陣樹定理+高斯消元+拉格朗日插值)

題意:有n個點,m條有顏色的邊,顏色為紅色藍色和綠色,對於所有滿足r+b+g=n1的三元組(r,b,g),求恰有r條紅色的邊,b條藍色的邊,g條綠色的邊的生成樹個數。

題解: 生成樹計數基本上就是矩陣樹定理啦。 我們可以給每一種顏色賦一個額外的值(在矩陣樹定理的時候鄰接矩陣和度數矩陣就加這個值),在這裡我們給紅邊設為x,藍邊設為xn,綠邊設為1,我們會發現當我們再去給這些邊去搞矩陣樹定理的時候就會發現得到的答案是一個關於xn2次多項式,然後我們會發現xbn+r(0r<n)表示的就是恰有r條紅色的邊,

b條藍色的邊,g條綠色的邊的生成樹個數。所以我們就可以進行n2次矩陣樹定理+高斯消元,每次給x附一個不同的值(我是用1n2),然後再拉格朗日插值求出這個多項式的每一個項的係數,於是就解決了這個問題啦。 如果有誤在評論區吼一聲哦! 程式碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
int n,m,u[2510],v[2510],clr[2510],a[60][60],f[2510],F[2][2510
],ans[2510]; int qpow(int x,int n){ int ret=1; while(n){ if(n&1) ret=1ll*ret*x%mod; x=1ll*x*x%mod; n>>=1; } return ret; } void Plus(int &a,int b){ a+=b; if(a>=mod) a-=mod; return; } void Minus(int &a,int b){ a-=b; if
(a<0) a+=mod; return; } int gauss(int n){ int ret=1; for(int i=1;i<n;i++){ for(int j=i+1;j<=n;j++){ if(!a[i][i]) return 0; if(!a[j][i]) continue; int tmp=1ll*a[j][i]*qpow(a[i][i],mod-2)%mod; for(int k=i;k<=n;k++) Minus(a[j][k],1ll*a[i][k]*tmp%mod); } } for(int i=1;i<=n;i++) ret=1ll*ret*a[i][i]%mod; return ret; } void lagrange(int n){ F[0][0]=1; for(int i=1;i<=n;i++){ memset(F[i&1],0,sizeof(F[i&1])); for(int j=0;j<i;j++){ Plus(F[i&1][j+1],F[i&1^1][j]); Plus(F[i&1][j],1ll*F[i&1^1][j]*(mod-i)%mod); } } for(int i=1;i<=n;i++){ int tmp=1; for(int j=1;j<=n;j++) if(i!=j) tmp=1ll*tmp*(i-j+mod)%mod; tmp=1ll*qpow(tmp,mod-2)*f[i]%mod; memcpy(F[n&1^1],F[n&1],sizeof(F[n&1])); for(int j=n;j;j--){ Plus(ans[j-1],1ll*F[n&1^1][j]*tmp%mod); if(j>0) Plus(F[n&1^1][j-1],1ll*F[n&1^1][j]*i%mod); } } return; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%d",u+i,v+i,clr+i); for(int i=1;i<=n*n;i++){ memset(a,0,sizeof(a)); for(int k=1;k<=m;k++){ if(clr[k]==1) Minus(a[u[k]][v[k]],i),Minus(a[v[k]][u[k]],i),Plus(a[u[k]][u[k]],i),Plus(a[v[k]][v[k]],i); else if(clr[k]==2){ int tmp=qpow(i,n); Minus(a[u[k]][v[k]],tmp),Minus(a[v[k]][u[k]],tmp),Plus(a[u[k]][u[k]],tmp),Plus(a[v[k]][v[k]],tmp); } else Minus(a[u[k]][v[k]],1),Minus(a[v[k]][u[k]],1),Plus(a[u[k]][u[k]],1),Plus(a[v[k]][v[k]],1); } f[i]=gauss(n-1); } lagrange(n*n); for(int i=0;i<n;i++) for(int j=0;i+j<n;j++) printf("%d\n",ans[i+j*n]); return 0; }