BZOJ 2467: [中山市选2010]生成树(矩阵树定理+取模高斯消元)
http://www.lydsy.com/JudgeOnline/problem.php?id=2467
题意:
思路:
要用矩阵树定理不难,但是这里的话需要取模,所以是需要计算逆元的,但是用辗转相减会更简单。
引用一大神博客里的介绍:http://blog.csdn.net/u013010295/article/details/47451451
值得一提的是,有些题目要求行列式模上一个数的结果。怎么求模意义下的行列式呢?这些题答案都比较大,用浮点数的话精度达不到要求,确实是一个问题。(显然强行用高精度分数类直接消元,最后再取模是可以的,但实现起来就复杂了)
我们注意到最后行列式是主对角线上的元素乘积再取模,根据同余定理,我们只需要对这些元素取模后的结果再相乘,就能得到相同的结果。因此我们可以采用在模意义下对矩阵消元的方法。然而消元过程中我们不可避免地要计算当前列的主元间的比值,这要用到除法;但另一方面,只有加法、减法、乘法操作才能保证同余,怎么在带有除法操作的条件下取模呢?
如果模的数是个质数(其实只需要模数和除数互质),对于除法我们可以直接变成乘上除数的逆元,根据费马小定理,这个逆元可以用快速幂简单求出来。如果模数不是质数,这就比较复杂了,我们在此介绍一种简单的方法。
我们知道,如果对于两个正数,不断地把较大的数减去较小的数,最后一定会有一个数为0。你可能已经知道,这就是辗转相减法的过程。同样地,我们对于矩阵中的两行,不断地把主元较大的那一行减去主元较小的那一行,最终一定有一行主元为0,也就是完成了消元(注意这里的减法是模意义下的减法)。而且这一过程是不改变行列式的。
(需要说明的是,一般情况下,矩阵中可能会有主元为负数的情况,这时我们简单的“大数减小数”显然是不行了。你可能会想到,要对正负数的各种情况判断一下,分别改为加法和减法操作。然而,这里我们讨论的是模意义下的矩阵消元,矩阵的元素都是正整数,并不存在这个问题。)
这样的减法效率还不够高,显然,如果两个主元相差太大,我们需要不断地用一行减去另一行。我们可以记录下两个主元相除的商x(这里用的是整数除法,当不能整除的时候向上向下取整都可以,由于计算机内部的整数除法实现,我们一般是向下取整,而且也符合我们取商的直觉,下面复杂度计算的是向下取整的做法),一次性用主元较大的行减去主元较小的行乘上x倍,这样效率就大大提高了。我们这样做的复杂度是多少呢?其实你也许已经发现,这一过程实际上就是辗转相除法,所以时间复杂度是O(log(n))的。
- #include<iostream>
- #include<algorithm>
- #include<cstring>
- #include<cstdio>
- #include<sstream>
- #include<vector>
- #include<stack>
- #include<queue>
- #include<cmath>
- #include<map>
- #include<set>
- using namespace std;
- typedef long long ll;
- typedef pair<int,ll> pll;
- const int INF = 0x3f3f3f3f;
- const int maxn=+;
- int n;
- int C[maxn][maxn];
- int Gauss()
- {
- for(int i=;i<=n;i++)
- for(int j=;j<=n;j++)
- C[i][j]=(C[i][j]+)%;
- int ans=;
- for(int i=;i<=n;i++) //当前行
- {
- for(int j=i+;j<=n;j++) //当前行之后的每一行
- {
- while(C[j][i]) //利用gcd的方法,不停地进行辗转相除
- {
- int tmp=C[i][i]/C[j][i];
- for(int k=i;k<=n;k++) C[i][k]=(C[i][k]-tmp*C[j][k])%;
- for(int k=i;k<=n;k++) swap(C[i][k],C[j][k]);
- ans=-ans;
- }
- }
- if(C[i][i]==) return ;
- ans=(ans*C[i][i])%;
- }
- ans=(ans+)%;
- return ans;
- }
- int main()
- {
- //freopen("in.txt","r",stdin);
- int T;
- scanf("%d",&T);
- while(T--)
- {
- memset(C,,sizeof(C));
- scanf("%d",&n);
- int cnt=n;
- for(int i=;i<=n;i++)
- {
- C[i][i]+=;
- C[i][i%n+]+=-;
- C[i][(i-)>=?i-:n]+=-;
- }
- for(int i=;i<=n;i++)
- {
- cnt++;
- C[i][cnt]=C[cnt][i]+=-;
- C[cnt][cnt]+=;
- C[cnt][cnt+]+=-;
- C[cnt+][cnt]+=-;
- cnt++;
- C[cnt][cnt]+=;
- C[cnt][cnt+]+=-;
- C[cnt+][cnt]+=-;
- cnt++;
- C[cnt][cnt]+=;
- C[cnt][i%n+]+=-;
- C[(i+)<=n?i+:][cnt]+=-;
- }
- n=cnt-;
- printf("%d\n",Gauss());
- }
- return ;
- }
BZOJ 2467: [中山市选2010]生成树(矩阵树定理+取模高斯消元)的更多相关文章
- 【bzoj2467】[中山市选2010]生成树 矩阵树定理
题目描述 有一种图形叫做五角形圈.一个五角形圈的中心有1个由n个顶点和n条边组成的圈.在中心的这个n边圈的每一条边同时也是某一个五角形的一条边,一共有n个不同的五角形.这些五角形只在五角形圈的中心的圈 ...
- BZOJ 2467: [中山市选2010]生成树 [组合计数]
2467: [中山市选2010]生成树 Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 638 Solved: 453[Submit][Status][ ...
- BZOJ 2467: [中山市选2010]生成树
有一种图形叫做五角形圈.一个五角形圈的中心有1个由n个顶点和n条边组成的圈.在中心的这个n边圈的每一条边同时也是某一个五角形的一条边,一共有n个不同的五角形.这些五角形只在五角形圈的中心的圈上有公共的 ...
- BZOJ 2467 [中山市选2010]生成树(组合数学)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2467 [题目大意] 有一种图形叫做五角形圈.一个五角形圈的中心有1个由n个顶点和n条边 ...
- BZOJ_2467_[中山市选2010]生成树_数学
BZOJ_2467_[中山市选2010]生成树_数学 [Submit][Status][Discuss] Description 有一种图形叫做五角形圈.一个五角形圈的中心有1个由n个顶点和n条边组成 ...
- bzoj 4031: 小Z的房间 矩阵树定理
bzoj 4031: 小Z的房间 矩阵树定理 题目: 你突然有了一个大房子,房子里面有一些房间.事实上,你的房子可以看做是一个包含n*m个格子的格状矩形,每个格子是一个房间或者是一个柱子.在一开始的时 ...
- 2019.01.02 bzoj2467: [中山市选2010]生成树(矩阵树定理)
传送门 矩阵树定理模板题. 题意简述:自己看题面吧太简单懒得写了 直接构建出这4n4n4n个点然后按照题面连边之后跑矩阵树即可. 代码: #include<bits/stdc++.h> # ...
- [bzoj2467][中山市选2010]生成树_快速幂
生成树 bzoj-2467 中山市选2010 题目大意:题目链接 注释:略. 想法:首先,考虑生成树的性质.每两个点之间有且只有一条路径.我们将每个五边形的5条边分为外面的4条边和内部的一条边,在此简 ...
- bzoj 2468: [中山市选2010]三核苷酸
2468: [中山市选2010]三核苷酸 Description 三核苷酸是组成DNA序列的基本片段.具体来说,核苷酸一共有4种,分别用’A’,’G’,’C’,’T’来表示.而三核苷酸就是由3个核苷酸 ...
随机推荐
- Celery框架简单实例
Python 中可以使用Celery框架 Celery框架是提供异步任务处理的框架,有两种用法,一种:应用程式发布任务消息,后台Worker监听执行,好处在于不影响应用程序继续执行.第二种,设置定时执 ...
- 虚拟机VMware的网络设置出了问题会导致很多莫名的错误
邪门地CentOS内软件安装失败问题:Xshell与虚拟机的各种连接失败:CentOS下eth0没显示ip地址. 这些原因竟然是一个,虚拟机VMware的网络设置出了问题. 恢复初始设置即可.
- 使用java进行excel读取和写入
1:添加处理excel的依赖jar包 <!-- 引入poi,解析workbook视图 --> <dependency> <groupId>org.apache.po ...
- mount –o remount,rw /
mount –o remount,rw / 重新挂载为已经挂载了的文件系统(以读写权限挂载),需要注意的是,挂载点必须是一个已经存在的目录,这个目录可以不为空.一般用于此目录下的文件为ro权限,需要临 ...
- hdu2159FATE(二维背包)
http://acm.hdu.edu.cn/showproblem.php?pid=2159 Problem Description 最近xhd正在玩一款叫做FATE的游戏,为了得到极品装备,xhd在 ...
- mysql 常用命令 常用SQL语句
维护命令 数据库 ##创建数据库 mysql> create database test; Query OK, 1 row affected ##删除数据库 mysql> drop dat ...
- Java中将xml文件转化为json的两种方式
原文地址https://blog.csdn.net/a532672728/article/details/76312475 最近有个需求,要将xml转json之后存储在redis中,找来找去发现整体来 ...
- 当输入域失去焦点 (blur) 时改变其颜色
$("input").blur(function(){ $("input").css("background-color","#D ...
- chrome浏览器使用
1.如何打开多个历史网页.这个需求是这样的,有时候开了多个网页查找资料,但是又还没有做完,然后又需要重启电脑.显然重启电脑后再开启浏览器,一般都是显示浏览器的主页了,上次开的那些网页全部在历史记录里面 ...
- ac1097
判断线段与直线的相交 这里有个地方需要注意的就是在 转换的时候容易报错 在叉积完后的判断符号的时候需要注意 这个地方会超出int 的范围 2014-06-0320:14:04 #include &l ...