6461. 【GDOI2020模拟02.05】生成树(矩阵树及其扩展、二维拉格朗日插值)

题目描述

给定一张 N 个点,M 条边的无向图,边有红、绿、蓝三种颜色,分别用 1,2,3 表示。

求这张图有多少生成树,满足绿色边数量不超过 x,蓝色边数量不超过 y,答案对10^9 + 7 取模。

1 ≤ N ≤ 40,1 ≤ M ≤ 10^5,1 ≤ ci ≤ 3

行列式

定义矩阵A的行列式det(A)或|A|

\(|A|=\sum_{排列p}{(-1)^{p的逆序对个数}\prod{A_{i,p[i]}}}\)

行列式的性质

(\(A\)的转置矩阵\(A^T\):把\(A\)的行列互换)

①\(|A|=|A^T|\)

②\(|A||B|=|AB|\)

https://www.zhihu.com/question/48497108

③\(|A的某一行乘x|=x|A|\)

④\(|A的某行第j项=aj+bj|=|A的某行第j项=aj|+|A的某行第j项=bj|\)

⑤交换相邻两行行列式变号

因为在每一种排列中符号都会改变

⑥交换任意两行行列式变号

两两依次交换的次数为2k+1,根据⑤可得必然变号

⑦有两行完全相同时行列式为0

否则交换两行后行列式改变

⑧把某一行乘k后加到另一行上行列式不变

相当于左乘了一个对角线为1,某个位置为k的矩阵, 这个矩阵的行列式显然是1

根据②可知不变

⑨上三角矩阵的行列式为对角线的积

其实可以不用化成上三角矩阵,只需要消元后n^2算逆序对即可

有了上面这些定理即可把矩阵高斯消元后求得行列式

(注意某行单独乘x时最终的结果要乘上x)

矩阵树定理

余子式:\(M_{i,j}\)表示矩阵\(A\)去掉第i行第j列后剩余矩阵的行列式

基尔霍夫矩阵:最简单的形式即为 度数矩阵D-邻接矩阵C,其中度数矩阵\(D_{i,i}=\)i的度数

其实度数矩阵的真正形态是这样的:\(D_{i,i}=\sum_{i≠j}{C[i][j]}\)

所以当Ci,j不为1,甚至是一个多项式时也是成立的

矩阵树定理:图的生成树个数=基尔霍夫矩阵的任意余子式\(M_{i,i}\)

我也不会证

二维拉格朗日插值

已知x=xi,y=yj时的点值\(a_{x_iy_j}\),构造\(\sum_{i,j}{a_{x_iy_j}f_{x_i}(x)}g_{x_i}(x)\)使得\(x=x_i\)时\(f_{x_i}(x)=1\),否则=0,g同理

可以发现和一维的一模一样,\(f_{x_i}(x)=\prod_{j≠i}{\frac{x-x_j}{x_i-x_j}}\)

题解

知道了上面的这题就是模板题了

设三种边边权为1,x,y,那么答案就是\(x^Xy^Y\)(XY为输入的数)的系数

枚举xy,求出行列式后插值即可

code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define mod 1000000007
#define Mod 1000000005
#define file
using namespace std;

long long A[41][41];
int a[41][41][3];
long long b[41][41];
long long c[41][41];
long long g[41];
long long ans[41][41];
int f[41];
int F[41];
int n,m,X,Y,i,j,k,l,x,y;
long long s,Ans;

long long qpower(long long a,int b)
{
    long long ans=1;

    while (b)
    {
        if (b&1)
        ans=ans*a%mod;

        a=a*a%mod;
        b>>=1;
    }

    return ans;
}

int main()
{
    freopen("tree.in","r",stdin);
    #ifdef file
    freopen("tree.out","w",stdout);
    #endif

    scanf("%d%d%d%d",&n,&m,&X,&Y);
    fo(i,1,m)
    scanf("%d%d%d",&j,&k,&l),--l,++a[j][k][l],++a[k][j][l];

    fo(x,0,n-1)
    {
        fo(y,0,n-1)
        {
            A[x][y]=1;

            fo(i,1,n)
            {
                b[i][i]=0;

                fo(j,1,n)
                if (i!=j)
                b[i][j]=-(a[i][j][0]+a[i][j][1]*x+a[i][j][2]*y),b[i][i]-=b[i][j];
            }

            memset(f,0,sizeof(f));
            fo(i,1,n-1)
            {
                fo(j,1,n-1)
                if (b[i][j])
                {
                    if (!f[j])
                    {
                        A[x][y]=A[x][y]*b[i][j]%mod;

                        b[i][j]=qpower(b[i][j],Mod);
                        fo(k,j+1,n-1)
                        b[i][k]=b[i][k]*b[i][j]%mod;
                        b[i][j]=1;

                        f[j]=i;
                        F[i]=j;

                        fo(k,1,i-1)
                        if (F[k]>F[i])
                        A[x][y]=-A[x][y];
                        break;
                    }
                    else
                    {
                        fo(k,j+1,n-1)
                        b[i][k]=(b[i][k]-b[i][j]*b[f[j]][k])%mod;
                        b[i][j]=0;
                    }
                }

                if (j>n-1)
                {
                    A[x][y]=0;
                    break;
                }
            }
        }
    }

    fo(i,0,n-1)
    {
        c[i][0]=s=1;

        fo(j,0,n-1)
        if (i!=j)
        {
            memset(g,0,sizeof(g));
            s=s*(i-j)%mod;

            fo(k,0,n-2)
            {
                g[k]=(g[k]-c[i][k]*j)%mod;
                g[k+1]=(g[k+1]+c[i][k])%mod;
            }
            fo(k,0,n-1) c[i][k]=g[k];
        }

        s=qpower(s,Mod);
        fo(j,0,n-1)
        c[i][j]=c[i][j]*s%mod;
    }

    fo(i,0,n-1)
    {
        memset(g,0,sizeof(g));
        fo(j,0,n-1)
        {
            fo(k,0,n-1)
            g[k]=(g[k]+c[j][k]*A[i][j])%mod;
        }

        fo(j,0,n-1)
        {
            fo(k,0,n-1)
            ans[j][k]=(ans[j][k]+c[i][j]*g[k])%mod;
        }
    }

    fo(i,0,X)
    {
        fo(j,0,Y)
        Ans=(Ans+ans[i][j])%mod;
    }

    printf("%lld\n",(Ans+mod)%mod);

    fclose(stdin);
    fclose(stdout);

    return 0;
}

原文地址:https://www.cnblogs.com/gmh77/p/12359839.html

时间: 2024-10-06 22:07:12

6461. 【GDOI2020模拟02.05】生成树(矩阵树及其扩展、二维拉格朗日插值)的相关文章

【编程题目】求一个矩阵中最大的二维矩阵(元素和最大)

35.(矩阵)求一个矩阵中最大的二维矩阵(元素和最大).如:1 2 0 3 42 3 4 5 11 1 5 3 0中最大的是:4 55 3要求:(1)写出算法;(2)分析时间复杂度;(3)用 C 写出关键代码 早上灭小题! /* 35.(矩阵) 求一个矩阵中最大的二维矩阵(元素和最大).如: 1 2 0 3 4 2 3 4 5 1 1 1 5 3 0 中最大的是: 4 5 5 3 要求:(1)写出算法;(2)分析时间复杂度;(3)用 C 写出关键代码 */ #include <stdio.h>

IT公司100题-35- 求一个矩阵中最大的二维矩阵(元素和最大)

问题描述: 求一个矩阵中最大的二维矩阵(元素和最大).如: 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 中最大的是: 4 5 9 10 分析: 2*2子数组的最大和.遍历求和,时间复杂度为O(mn). 代码实现: 1 // 35.cc 2 #include <iostream> 3 #include <climits> 4 using namespace std; 5 6 int find_max(int (*a)[5], int m, int n) { 7 in

矩阵中求最大二维矩阵

1.求一个矩阵中最大的二维矩阵(元素和最大).如: 1 2 0 3 4 2 3 4 5 1 1 1 5 3 0 中最大的是: 4 5 5 3 要求:(1)写出算法;(2)分析时间复杂度; function struct($arr, $row, $col) { $sum=0; for ($i=0;$i<$row-1;$i++){ for ($j=0;$j<$col;$j++){ $sum1=$arr[$i][$j]+$arr[$i][$j+1]+$arr[$i+1][$j]+$arr[$i+1]

【bzoj2467】[中山市选2010]生成树 矩阵树定理

题目描述 有一种图形叫做五角形圈.一个五角形圈的中心有1个由n个顶点和n条边组成的圈.在中心的这个n边圈的每一条边同时也是某一个五角形的一条边,一共有n个不同的五角形.这些五角形只在五角形圈的中心的圈上有公共的顶点.如图0所示是一个4-五角形圈. 现在给定一个n五角形圈,你的任务就是求出n五角形圈的不同生成树的数目.还记得什么是图的生成树吗?一个图的生成树是保留原图的所有顶点以及顶点的数目减去一这么多条边,从而生成的一棵树. 注意:在给定的n五角形圈中所有顶点均视为不同的顶点. 输入 输入包含多

HDU 1892(树状数组二维)

See you~ Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 4167    Accepted Submission(s): 1311 Problem Description Now I am leaving hust acm. In the past two and half years, I learned so many kn

jzoj2701 【GDKOI2012模拟02.01】矩阵

传送门:https://jzoj.net/senior/#main/show/2701 [题目大意] 给出矩阵A,求矩阵B,使得 最小,矩阵B每个元素在[L,R]内 n<=200,1<=Aij,L,R<=1000, L<=R [题解] 我们二分答案x,然后对行列建点,每行向每列连[L,R]的边,然后S向每行连[max(S[i]-x), S[i]+x]的边,每列向T连[max(T[i]-x), T[i]+x]的边,判断是否有可行流即可. 其中S[i]表示A中第i行的和,T[i]表示A

6467. 【GDOI2020模拟02.09】西行寺无余涅槃(FWT的性质)

题目描述 题解 吼题 推荐博客:https://www.cnblogs.com/jz-597/p/12300760.html 最暴力的做法是把n个2^m的FWT乘起来,这样显然不行 先把pi,1~k异或上pi,1,把pi,1变为0,最后再把pi,1异或回去 考虑FWT(xor)的本质,tr(A)=(tr(A1)+tr(A2),tr(A1)-tr(A2)),倒着做可以发现只有变换的u和u+2^k(u&2^k=0)只有u+2^k--->u+2^k这一操作时才需要变号 要求FWT(A)i,就等于把

6476. 【GDOI2020模拟02.19】A

题目 题目比较简洁,就不复述了. 思考历程 这让我联想到了不久之前在CF上做的一道题. 但这两道题的差别是很大的,共同点并不是很多. 直接套那题的方法在这题中也顶多拿个40分. 考虑探索新大陆,然而没有成功-- 感觉这题的暴力不好打,最终也没有打部分分-- (所以说我在这题上耗费了1h) 正解 正解的思路比较清奇. 不用说也知道这题要容斥一下,我比赛时一直在想着保留上界,然而正解是保留下界. 如果想到的话也挺显然的,首先用最终的值减去下界,接下来用生成函数去考虑,就相当于\(\frac{1}{(

6476. 【GDOI2020模拟02.19】A(范德蒙恒等式)

题目描述 题解 镇♂男则反 容斥下界,上界开到大概505位,数位dp最终的和V 设边界(要大于边界)之和为S,那么答案为C(V-S-1,n-1) 根据范德蒙恒等式,C(n+m,k)=∑C(n,i)*C(m,k-i) 如果nm都是正数很好证明,把n+m分成n和m两部分,枚举n部分选择个数组合一下 这个式子其实可以拓展到负数,证明要用生成函数 关于n为负数的组合数:\(C(n,m)=n^{\underline{m}}/m!\),其实和正数时是一样的 (注意这只是为了计算范德蒙恒等式而扩展的,在一般情