• LOJ6271 [长乐集训 2017 Day10] 生成树求和 加强版


    先对三进制下的每一位进行考虑,类似 CF917D Stranger Trees 一样,对每条边赋权为 (1,x,x^2),矩阵树定理求行列式后用高斯消元或者插值求出多项式即可,但这样复杂度为 (O(n^4 log n))。因为循环卷积意义下的多项式的有用次数比较小,考虑直接代入多项式来求行列式,这里多项式的运算为模 (x^3) 意义下的循环卷积,代入 (3) 次单位根即可, (3) 次单位根有个性质:(omega_3^2=omega_3-1),用二元组 ((a,b)) 来表示一个数 (a+bomega_3),得其逆元为:

    [large frac{1}{a+bomega_3}=frac{a-b-bomega_3}{(a+bomega_3)(a-b-bomega_3)}=frac{a-b}{a^2+b^2-ab}-frac{b}{a^2+b^2-ab}omega_3 ]

    实际上因为 (3) 在本题的模数中存在二次剩余,因此二元组 ((a,b)) 也可以直接表示复数 (a+bi)。总复杂度为 (O(n^3log n))

    #include<bits/stdc++.h>
    #define maxn 210
    #define maxm 40010
    #define p 1000000007
    using namespace std;
    typedef long long ll;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n,m,mx;
    ll ans;
    struct edge
    {
        int x,y,v;
        edge(int a=0,int b=0,int c=0)
        {
            x=a,y=b,v=c;
        }
    }e[maxm];
    ll inv(ll x)
    {
        ll v=1,y=p-2;
        while(y)
        {
            if(y&1) v=v*x%p;
            x=x*x%p,y>>=1;
        }
        return v;
    }
    struct node
    {
        ll a,b;
        node(ll x=0,ll y=0)
        {
            a=x,b=y;
        }
        node get()
        {
            ll v=inv(a*a%p+b*b%p-a*b%p+p);
            return node((a-b+p)*v%p,(p-b)*v%p);
        }
        bool empty()
        {
            return !a&&!b;
        }
    }a[maxn][maxn],w[5],f[5],g[5];
    node operator + (const node &x,const node &y)
    {
        return node((x.a+y.a)%p,(x.b+y.b)%p);
    }
    node operator - (const node &x,const node &y)
    {
        return node((x.a-y.a+p)%p,(x.b-y.b+p)%p);
    }
    node operator * (const node &x,const node &y)
    {
        return node((x.a*y.a%p-x.b*y.b%p+p)%p,(x.a*y.b%p+x.b*y.a%p-x.b*y.b%p+p)%p);
    }
    node det()
    {
        node v=node(1,0);
        for(int i=2;i<=n;++i)
        {
            if(a[i][i].empty())
            {
                for(int j=i+1;j<=n;++j)
                {
                    if(!a[j][i].empty())
                    {
                        swap(a[i],a[j]),v=node(0,0)-v;
                        break;
                    }
                }
            }
            if(a[i][i].empty()) return node(0,0);
            node iv=a[i][i].get();
            for(int j=i+1;j<=n;++j)
            {
                node d=a[j][i]*iv;
                for(int k=i;k<=n;++k) a[j][k]=a[j][k]-a[i][k]*d;
            }
            v=v*a[i][i];
        }
        return v;
    }
    int main()
    {
        freopen("sum.in","r",stdin);
        freopen("sum.out","w",stdout);
        read(n),read(m),w[0]=w[3]=node(1,0),w[1]=node(0,1),w[2]=node(p-1,p-1);
        for(int i=1;i<=m;++i)
            read(e[i].x),read(e[i].y),read(e[i].v),mx=max(mx,e[i].v);
        for(int k=1;k<=mx;k*=3)
        {
            for(int i=0;i<3;++i)
            {
                memset(a,0,sizeof(a));
                for(int j=1;j<=m;++j)
                {
                    int x=e[j].x,y=e[j].y;
                    node v=w[e[j].v/k%3*i%3];
                    a[x][x]=a[x][x]+v,a[y][y]=a[y][y]+v;
                    a[x][y]=a[x][y]-v,a[y][x]=a[y][x]-v;
                }
                f[i]=det(),g[i]=node(0,0);
            }
            for(int i=0;i<3;++i)
                for(int j=2;j>=0;--j)
                    g[i]=g[i]*w[3-i]+f[j];
            ans=(ans+(g[1].a+g[2].a*2)*inv(3)%p*k%p)%p;        
        }
        printf("%lld",ans);   
        return 0;
    }
    
  • 相关阅读:
    章节八、2-火狐的插件TryXPath
    章节八、1-如何使用火狐开发者工具来查找元素
    章节七、6-Map集合的区别
    章节七、5-Maps
    章节七、4-Sets
    章节七、3-ArrayList和LinkedList对比
    章节七、2-Linked List
    jQuery中$符号的作用
    jQuery基础的HTML与text区别
    推荐一些github上的免费好书
  • 原文地址:https://www.cnblogs.com/lhm-/p/14451414.html
Copyright © 2020-2023  润新知