[loj6271]生成树求和

将每一位拆开考虑,即不妨假设$0le 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$看作一个符号)

展开后,也就得到了如下的三元一次方程组
$$
egin{cases}ad+bf+ce=0\ ae+bd+cf=1\af+be+cd=0end{cases}
$$
通过一些计算,可以解得即
$$
egin{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 e b$或$b e c$且$a+b+c e 0$($a+b+c otequiv 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 } 
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/14480953.html