【XSY1537】五顏六色的幻想鄉(矩陣樹定理+高斯消元+拉格朗日插值)
阿新 • • 發佈:2018-12-10
題意:有個點,條有顏色的邊,顏色為紅色藍色和綠色,對於所有滿足的三元組,求恰有條紅色的邊,條藍色的邊,條綠色的邊的生成樹個數。
題解:
生成樹計數基本上就是矩陣樹定理啦。
我們可以給每一種顏色賦一個額外的值(在矩陣樹定理的時候鄰接矩陣和度數矩陣就加這個值),在這裡我們給紅邊設為,藍邊設為,綠邊設為,我們會發現當我們再去給這些邊去搞矩陣樹定理的時候就會發現得到的答案是一個關於的次多項式,然後我們會發現表示的就是恰有條紅色的邊, 條藍色的邊,條綠色的邊的生成樹個數。所以我們就可以進行次矩陣樹定理+高斯消元,每次給附一個不同的值(我是用到),然後再拉格朗日插值求出這個多項式的每一個項的係數,於是就解決了這個問題啦。
如果有誤在評論區吼一聲哦!
程式碼:
#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;
}