首页 > 其他分享 >【GDOI2020模拟02.05】生成树 (矩阵树扩展)

【GDOI2020模拟02.05】生成树 (矩阵树扩展)

时间:2023-05-09 18:32:10浏览次数:46  
标签:ni 02.05 mo 矩阵 int GDOI2020 ans ll fo

Description:

给定一张 N 个点,M 条边的无向图,边有红、绿、蓝三种颜色,分别用 1,2,3 表示。
求这张图有多少生成树,满足绿色边数量不超过 x,蓝色边数量不超过 y,答案对10^9 + 7 取模。

n<=40

题解:

考虑正常的用矩阵树求生成树个数的方法。

基尔霍夫矩阵里的每个位置只是一个数,事实上可以把它扩展成一个多项式。

在这题中,每个位置就是一个\(系数*x^{...}*y^{...}\)。

然后求出这个矩阵的余子式的行列式就好了。

当然这个矩阵是不好高斯消元去求行列式的,但是我们可以拉格朗日插值。

二维拉格朗日插值:

\(\sum_{i,j} a_{x_i,y_j}\prod_{k \not= i{x - xk\over xi-xk}}\prod_{k \not= j{y - yk\over yj-yk}}\)

和一维没有什么区别,

我们需要暴力展开这个式子,直接搞的复杂度是\(O(n^4)\),加上高斯消元的\(O(n^5)\)能够通过。

这题比较特殊,可以使\(y=x^n\)去做一维插值,我比赛时写的一维插值:
\(\sum_{i,j}a_{xi}\prod_{k \not= i{x - xk\over xi-xk}}\)

这格东西有\(O(n^2)\)项,如果对后面的暴力展开,总共是\(O(n^6)\),需要卡常才能通过。

可以用除法优化,注意除一次也就\(O(n^2)\),总共\(O(n^4)\)。

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

const int mo = 1e9 + 7;

ll ksm(ll x, ll y) {
	ll s = 1;
	for(; y; y /= 2, x = x * x % mo)
		if(y & 1) s = s * x % mo;
	return s;
}

const int N = 41;

int n;

ll a[N][N];

ll solve() {
	fo(i, 1, n) a[i][n] = a[n][i] = 0;
	n --;
	ll ans = 1;
	fo(i, 1, n) {
		int u = -1;
		fo(j, i, n) if(a[j][i])
			{ u = j; break;}
		if(u == -1) continue;
		if(u > i) {
			ans = -ans;
			fo(j, 1, n) swap(a[i][j], a[u][j]);
		}
		ll ni = ksm(a[i][i], mo - 2);
		fo(j, i + 1, n) if(a[j][i]) {
			ll v = -ni * a[j][i] % mo;
			fo(k, 1, n) a[j][k] = (a[j][k] + a[i][k] * v) % mo;
		}
	}
	fo(i, 1, n) ans = ans * a[i][i] % mo;
	ans = (ans % mo + mo) % mo;
	n ++;
	return ans;
}

int m, x, y, z;
int c1, c2;

ll p[3][N], q[3][N][N];

void Init() {
	scanf("%d %d %d %d", &n, &m, &c1, &c2);
	fo(i, 1, m) {
		scanf("%d %d %d", &x, &y, &z);
		if(x == y) continue;
		z --;
		p[z][x] ++; p[z][y] ++;
		q[z][x][y] ++; q[z][y][x] ++;
	}
}


ll cz(ll x) {
	memset(a, 0, sizeof a);
	ll x1 = x, x2 = ksm(x, n);
	fo(i, 1, n) {
		a[i][i] += p[0][i];
		a[i][i] += p[1][i] * x1 % mo;
		a[i][i] += p[2][i] * x2 % mo;
	}
	fo(i, 1, n) fo(j, 1, n) {
		a[i][j] -= q[0][i][j];
		a[i][j] -= q[1][i][j] * x1 % mo;
		a[i][j] -= q[2][i][j] * x2 % mo;
		a[i][j] %= mo;
	}
	return solve();
}

int t;

ll f[N * N], g[N * N], h[N * N];

ll ni[N * N];

void work() {
	t = n * (n - 1);
	fo(i, 0, t) ni[i] = ksm(i, mo - 2);
	
	g[0] = 1;
	fo(i, 0, t) {
		fd(j, i, 0) {
			g[j + 1] = (g[j + 1] + g[j]) % mo;
			g[j] = g[j] * -i % mo;
		}
	}
	
	fo(i, 0, t) {
		ll xs = cz(i);
		fo(j, 0, t) if(i != j)
			xs = xs * (i < j ? -ni[j - i] : ni[i - j]) % mo;
		
		fo(j, 0, t + 1) h[j] = g[j];
		fd(j, t + 1, 1) h[j - 1] = (h[j - 1] + h[j] * i) % mo;
		fo(j, 0, t) f[j] = (f[j] + xs * h[j + 1]) % mo;
	}
	
	ll ans = 0;
	fo(k, 0, t) {
		if(k % n <= c1 && k / n <= c2) {
			ans = (ans + f[k]) % mo;
		}
	}
	
	ans = (ans % mo + mo) % mo;
	pp("%lld\n", ans);
}

int main() {
	freopen("tree.in", "r", stdin);
	freopen("tree.out", "w", stdout);
	Init();
	work();
}

标签:ni,02.05,mo,矩阵,int,GDOI2020,ans,ll,fo
From: https://blog.51cto.com/u_16105286/6259845

相关文章

  • 杨氏矩阵学习小记
    参考资料:IOI2019国家预备队论文:袁方舟《浅谈杨氏矩阵在信息学竞赛中的应用》定义:杨图:一个n*m的矩阵。有些格子上有元素,有些没有。若一个格子没有元素,则它的右边和上边也没有元素。大概是一个锯齿状的东西:杨表:每个位置的元素是一个数字,且是一个排列。每一行的数从左到右递增,每一列的......
  • 2023-05-07:给你一个大小为 n x n 二进制矩阵 grid 。最多 只能将一格 0 变成 1 。 返
    2023-05-07:给你一个大小为nxn二进制矩阵grid。最多只能将一格0变成1。返回执行此操作后,grid中最大的岛屿面积是多少?岛屿由一组上、下、左、右四个方向相连的1形成。输入:grid=[[1,0],[0,1]]。输出:3。来自亚马逊、谷歌、微软、Facebook、Bloomberg。......
  • 2023-05-07:给你一个大小为 n x n 二进制矩阵 grid 。最多 只能将一格 0 变成 1 。 返
    2023-05-07:给你一个大小为nxn二进制矩阵grid。最多只能将一格0变成1。返回执行此操作后,grid中最大的岛屿面积是多少?岛屿由一组上、下、左、右四个方向相连的1形成。输入:grid=[[1,0],[0,1]]。输出:3。来自亚马逊、谷歌、微软、Facebook、Bloomberg。答案2023......
  • 矩阵加速递推
    首先矩阵快速幂模板structmatrix{staticconstexprintmod=1e9+7;intx,y;vector<vector<int>>v;matrix(){}matrix(intx,inty):x(x),y(y){v=vector<vector<int>>(x+1,vector<int>(y+1,0)......
  • 矩阵学习笔记
    定义我们把一个\(n\timesm\)的数列叫做矩阵。他可以解决一部分线性递推的题目。特别的,我们常说的向量就是一个\(1\timesn\)的矩阵捏。单位元我们形如这样\(\begin{bmatrix}1&0&0\\0&1&0\\0&0&1\end{bmatrix}\)这种只有对角线都是\(1\)的叫做单位元。运算主......
  • (DFS + 剪枝)剑指 Offer 12. 矩阵中的路径
    题目描述:给定一个 mxn二维字符网格 board和一个字符串单词 word。如果 word存在于网格中,返回true;否则,返回false。单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用......
  • LeetCode 59. 螺旋矩阵 II
    题目链接:LeetCode59.螺旋矩阵II本题不涉及算法,只是简单的模拟,但是由于边界条件比较多,因此容易出错。分析题干:题目要求按照右、下、左、上、这样的顺序对数组进行填充,填充的值为1~n*n,因此问题的关键就是找到待填充的位置,将其值赋值为i即可。由于填充的顺序是有规律的,因......
  • AcWing 754. 平方矩阵 II
    AcWing754.平方矩阵II1.地址https://www.acwing.com/problem/content/756/2.题解#include<iostream>#include<cstdio>#include<cmath>usingnamespacestd;//每个元素的值为:各个元素下标相减的绝对值+1intmain(){intmatrix[102][102];intn;......
  • 矩阵基础知识
    文章目录1.矩阵的一些基础知识1.1矩阵只有乘法1.2向量有点乘(也是内积)和叉乘:1.3单位向量1.4正交矩阵1.5线性无关和线性相关的向量1.6矩阵的逆1.7对称矩阵1.7矩阵的秩(rank)1.8伴随矩阵1.9矩阵的零空间1.10矩阵的扩展基定理1.矩阵的一些基础知识1.1矩阵只有乘法1.2向量......
  • sklearn.metrics.confusion_matrix—计算混淆矩阵来评估分类的准确性
    在分类模型的性能评估指标总结中,已讲过混淆矩阵形式,接下来将介绍如何通过sklearn库中的confusion_matrix函数快速获得混淆矩阵。语法格式sklearn.metrics.confusion_matrix(y_true, y_pred, *, labels=None, sample_weight=None, normalize=None)参数解释:y_true:真实标......