[loj6271]生成树求和
将每一位拆开考虑,即不妨假设$0\le c<3$
考虑矩阵树定理,即统计所有生成树边权乘积的和,但我们这里要将边权相加,很明显将其作为幂次(如果作为$cx+1$无法对3取模)
更具体的,也就是将每一个位置从1变为$x^{c}$,系数对$10^{9}+7$取模,相乘时幂次对3取模
另外,高斯消元时需要对该多项式求逆,考虑$(ax^{2}+bx+c)^{-1}$即找到$dx^{2}+ex+f$满足
$$
(ax^{2}+bx+c)(dx^{2}+ex+f)\equiv 1(mod\ x^{3}-1)
$$
(幂次对3取模等价于原多项式对$x^{3}-1$取模,关于这个正确性不证明也没关系,可以将这个对$x^{3}-1$看作一个符号)
展开后,也就得到了如下的三元一次方程组
$$
\begin{cases}ad+bf+ce=0\\ ae+bd+cf=1\\af+be+cd=0\end{cases}
$$
通过一些计算,可以解得即
$$
\begin{cases}d=\frac{b^{2}-ac}{a^{3}+b^{3}+c^{3}-3abc}\\e=\frac{a^{2}-bc}{{a^{3}+b^{3}+c^{3}-3abc}}\\f=\frac{c^{2}-ab}{{a^{3}+b^{3}+c^{3}-3abc}}\end{cases}
$$
根据$a^{3}+b^{3}+c^{3}-3abc=\frac{(a+b+c)((a-b)^{2}+(b-c)^{2}+(c-a)^{2})}{2}$,若其为0其实与原来的0多项式是一样的,因此要判定要求$a\ne b$或$b\ne c$且$a+b+c\ne 0$($a+b+c\not\equiv 0(mod\ 10^{9}+7)$
更特别的,在如果最后一个式子不满足上述条件,则还要乘上去
由此计算即可,时间复杂度为$o(n^{3}\log_{3}c)$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 105 4 #define mod 1000000007 5 struct Edge{ 6 int x,y,z; 7 }e[N*N]; 8 int n,m,ans; 9 int pow(int n,int m){ 10 int s=n,ans=1; 11 while (m){ 12 if (m&1)ans=1LL*ans*s%mod; 13 s=1LL*s*s%mod; 14 m>>=1; 15 } 16 return ans; 17 } 18 struct poly{ 19 int a[3]; 20 poly(){ 21 a[0]=a[1]=a[2]=0; 22 } 23 void init(){ 24 a[0]=a[1]=a[2]=0; 25 } 26 bool zero(){ 27 return (a[0]==a[1])&&(a[1]==a[2])||((0LL+a[0]+a[1]+a[2])%mod==0); 28 } 29 poly operator + (const poly &k)const{ 30 poly o; 31 for(int i=0;i<3;i++)o.a[i]=(a[i]+k.a[i])%mod; 32 return o; 33 } 34 poly operator - ()const{ 35 poly o; 36 for(int i=0;i<3;i++)o.a[i]=(mod-a[i])%mod; 37 return o; 38 } 39 poly operator * (const poly &k)const{ 40 poly o; 41 for(int i=0;i<3;i++) 42 for(int j=0;j<3;j++)o.a[(i+j)%3]=(o.a[(i+j)%3]+1LL*a[i]*k.a[j])%mod; 43 return o; 44 } 45 poly inv(){ 46 int s=mod-3LL*a[0]*a[1]%mod*a[2]%mod; 47 for(int i=0;i<3;i++)s=(s+1LL*a[i]*a[i]%mod*a[i])%mod; 48 s=pow(s,mod-2); 49 poly o; 50 o.a[0]=(1LL*a[0]*a[0]-1LL*a[1]*a[2]%mod+mod)%mod*s%mod; 51 o.a[1]=(1LL*a[2]*a[2]-1LL*a[0]*a[1]%mod+mod)%mod*s%mod; 52 o.a[2]=(1LL*a[1]*a[1]-1LL*a[0]*a[2]%mod+mod)%mod*s%mod; 53 return o; 54 } 55 }a[N][N]; 56 poly guess(){ 57 poly ans; 58 ans.a[0]=1; 59 for(int i=1;i<n;i++){ 60 int k=-1; 61 for(int j=i;j<n;j++) 62 if (!a[j][i].zero()){ 63 k=j; 64 break; 65 } 66 if (k<0)return ans*a[i][i]; 67 if (k!=i){ 68 ans=(-ans); 69 for(int j=i;j<n;j++)swap(a[i][j],a[k][j]); 70 } 71 ans=ans*a[i][i]; 72 for(int j=i+1;j<n;j++){ 73 poly o=a[j][i]*a[i][i].inv(); 74 for(int k=i;k<n;k++)a[j][k]=a[j][k]+(-o*a[i][k]); 75 } 76 } 77 return ans; 78 } 79 int main(){ 80 freopen("sum.in","r",stdin); 81 freopen("sum.out","w",stdout); 82 scanf("%d%d",&n,&m); 83 for(int i=1;i<=m;i++)scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].z); 84 int s=1; 85 while (1){ 86 bool flag=0; 87 for(int i=1;i<n;i++) 88 for(int j=1;j<n;j++)a[i][j].init(); 89 for(int i=1;i<=m;i++){ 90 poly o; 91 o.a[e[i].z%3]=1; 92 if (e[i].x<n)a[e[i].x][e[i].x]=a[e[i].x][e[i].x]+o; 93 if (e[i].y<n)a[e[i].y][e[i].y]=a[e[i].y][e[i].y]+o; 94 if ((e[i].x<n)&&(e[i].y<n)){ 95 a[e[i].x][e[i].y]=a[e[i].x][e[i].y]+(-o); 96 a[e[i].y][e[i].x]=a[e[i].y][e[i].x]+(-o); 97 } 98 if (e[i].z)flag=1; 99 e[i].z/=3; 100 } 101 if (!flag)break; 102 poly o=guess(); 103 ans=(ans+1LL*s*o.a[1]+2LL*s*o.a[2])%mod; 104 s=3LL*s%mod; 105 } 106 printf("%d",ans); 107 return 0; 108 }