题目1: SPOJ 2832

题目大意:

求一个矩阵行列式模一个数P后的值。p不一定是质数。

算法讨论:

因为有除法而且p不一定是质数,不一定有逆元,所以我们用辗转相除法。

 #include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm> using namespace std; const int N = ;
typedef long long ll; int n;
ll p, mat[N][N]; ll det(ll a[N][N]) {
ll res = ; for(int i = ; i <= n; ++ i) {
for(int j = i + ; j <= n; ++ j) {
while(a[j][i]) {
ll t = a[i][i] / a[j][i]; for(int k = i; k <= n; ++ k)
a[i][k] = (a[i][k] - a[j][k] * t) % p;
for(int k = i; k <= n; ++ k)
swap(a[i][k], a[j][k]);
res = -res;
}
}
if(a[i][i] == ) return ;
res = 1LL * res * a[i][i] % p;
}
return (res + p) % p;
} int main() {
while(~scanf("%d%lld", &n, &p)) {
for(int i = ; i <= n; ++ i) {
for(int j = ; j <= n; ++ j) {
scanf("%lld", &mat[i][j]);
mat[i][j] %= p;
}
}
printf("%lld\n", det(mat));
}
return ;
}

SPOJ 2832

题目2: BZOJ 1002 轮状病毒

题目大意:

一棵有规律的树,求其生成树的数量。基尔霍夫矩裸上。

关于矩阵树定理,有一个递推式: f[n] = 3 * f[n - 1] - f[n - 2] + 2;

高精度一下即可。

 #include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <iostream> using namespace std; const int rad = ; int n; struct BigInt {
int v[];
int len; BigInt() {
memset(v, , sizeof v);
len = ;
} friend BigInt operator + (BigInt a, BigInt b) {
int tmp = max(a.len, b.len); for(int i = ; i <= tmp; ++ i) {
a.v[i] += b.v[i];
if(a.v[i] >= rad) {
a.v[i + ] += a.v[i] / rad;
a.v[i] %= rad;
}
}
while(a.v[tmp + ]) tmp ++;
a.len = tmp; return a;
} friend BigInt operator * (BigInt a, BigInt b) {
BigInt c;
int tmp = a.len + b.len; for(int i = ; i <= a.len; ++ i) {
for(int j = ; j <= b.len; ++ j) {
c.v[i + j - ] += a.v[i] * b.v[j];
}
}
for(int i = ; i <= tmp; ++ i) {
if(c.v[i] >= rad) {
c.v[i + ] += c.v[i] / rad;
c.v[i] %= rad;
}
if(c.v[i]) c.len = i;
} return c;
} friend BigInt operator * (BigInt a, int k) {
for(int i = ; i <= a.len; ++ i) {
a.v[i] *= k;
}
for(int i = ; i <= a.len; ++ i) {
a.v[i + ] += a.v[i] / rad;
a.v[i] %= rad;
}
if(a.v[a.len + ]) a.len ++;
return a;
} friend BigInt operator - (BigInt a, BigInt b) {
for(int i = ; i <= a.len; ++ i) {
a.v[i] -= b.v[i];
if(a.v[i] < ) {
a.v[i + ] -= ;
a.v[i] += rad;
}
}
while(a.v[a.len] == )a.len --;
return a;
}
void getint(int k) {
while(k) {
v[++ len] = k % ;
k /= ;
}
} void print() {
for(int i = len; i >= ; -- i) {
printf("%d", v[i]);
}
}
}f[], cst; void Input() {
scanf("%d", &n);
} void Solve() {
f[].getint();
f[].getint();
cst.getint();
for(int i = ; i <= n; ++ i) {
f[i] = f[i - ] * - f[i - ] + cst;
}
} void Output() {
f[n].print();
} int main() {
Input();
Solve();
Output(); return ;
}

BZOJ 1002

题目3: SPOJ 104 HighWays

题目大意:

给一张图,求其生成树的个数。

算法讨论:裸上基尔霍夫。

 #include <cstdio>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <algorithm> using namespace std; typedef long long ll;
const int N = ; ll ans;
int n, m;
ll degree[N][N], G[N][N], self[N][N]; ll det(ll a[N][N]) {
ll res = ; for(int i = ; i < n; ++ i) {
for(int j = i + ; j < n; ++ j) {
while(a[j][i]) {
ll t = a[i][i] / a[j][i]; for(int k = i; k < n; ++ k)
a[i][k] = (a[i][k] - a[j][k] * t);
for(int k = i; k < n; ++ k)
swap(a[i][k], a[j][k]);
res = -res;
}
}
if(a[i][i] == ) return ;
res = 1LL * res * a[i][i];
}
return res;
} void Input() {
int x, y; memset(self, , sizeof self);
memset(degree, , sizeof degree); scanf("%d%d", &n, &m);
for(int i = ; i <= m; ++ i) {
scanf("%d%d", &x, &y);
degree[x][y] ++;
degree[y][x] ++;
self[x][x] ++; self[y][y] ++;
}
for(int i = ; i <= n; ++ i) {
for(int j = ; j <= n; ++ j) {
G[i][j] = self[i][j] - degree[i][j];
}
}
} void Solve() {
ans = det(G);
} void Output() {
printf("%lld\n", ans);
} int main() {
int t; scanf("%d", &t); while(t --) {
Input();
Solve();
Output();
} return ;
}

SPOJ 104

题目4: BZOJ 4031 [HEOI 2015] 小Z的房间

题目大意:并没有搞懂。只是抄的。河北的题还真是够呛。(PS:我是河北的)

算法讨论:裸上Matrix-Tree定理吧。

 #include <bits/stdc++.h>

 using namespace std;

 const int N = ;
const int mod = 1e9;
typedef long long ll; int n, m, cnt;
int p[N][N]; ll a[N * N][N * N];
int dx[]={, , , -};
int dy[]={, -, , };
char maze[N][N]; ll det() {
ll res = ; for(int i = ; i < cnt; ++ i)
for(int j = ; j < cnt; ++ j)
a[i][j] = (a[i][j] + mod) % mod;
for(int i = ; i < cnt; ++ i) {
for(int j = i + ; j < cnt; ++ j) {
while(a[j][i]) {
ll t = a[i][i] / a[j][i]; for(int k = i; k < cnt; ++ k)
a[i][k] = (a[i][k] - a[j][k] * t % mod + mod) % mod;
for(int k = i; k < cnt; ++ k)
swap(a[i][k], a[j][k]);
res = -res;
}
}
if(a[i][i] == ) return ;
res = 1LL * res * a[i][i] % mod;
}
return (res + mod) % mod;
} int main() {
scanf("%d%d", &n, &m);
for(int i = ; i <= n; ++ i) {
scanf("%s", maze[i] + );
}
for(int i = ; i <= n; ++ i)
for(int j = ; j <= m; ++ j)
if(maze[i][j] == '.')
p[i][j] = ++ cnt;
for(int i = ; i <= n; ++ i) {
for(int j = ; j <= m; ++ j) {
if(maze[i][j] != '.') continue;
for(int k = ; k < ; ++ k) {
int nx = dx[k] + i, ny = dy[k] + j; if(nx < || ny < || nx > n || ny > m || maze[nx][ny] != '.') continue;
int u = p[i][j], v = p[nx][ny]; a[u][u] ++; a[u][v] --;
}
}
}
printf("%lld\n", det());
return ;
}

BZOJ 4031

题目5: Uva 10766

题目大意:

求一个有根树的生成树的数量。

算法讨论:

其实这个有根和无根是一样的。直接做就行。

 #include <bits/stdc++.h>

 using namespace std;

 typedef long long ll;
const int N = ; int n, m, kk;
bool lk[N][N];
ll a[N][N]; ll det() {
ll res = ; for(int i = ; i < n; ++ i) {
for(int j = i + ; j < n; ++ j) {
while(a[j][i]) {
ll t = a[i][i] / a[j][i]; for(int k = i; k < n; ++ k)
a[i][k] = a[i][k] - a[j][k] * t;
for(int k = i; k < n; ++ k)
swap(a[i][k], a[j][k]);
res = -res;
}
}
if(a[i][i] == ) return ;
res = res * a[i][i];
} return abs(res);
} int main() {
int u, v; while(~scanf("%d%d%d", &n, &m, &kk)) {
memset(lk, false, sizeof lk);
memset(a, , sizeof a);
for(int i = ; i <= m; ++ i) {
scanf("%d%d", &u, &v);
lk[u][v] = lk[v][u] = true;
}
for(int i = ; i <= n; ++ i) {
int cnt = ; for(int j = ; j <= n; ++ j) {
if(i != j && !lk[i][j]) {
a[i][j] = -;
++ cnt;
}
}
a[i][i] = cnt;
}
printf("%lld\n", det());
} return ;
}

Uva 10766

题目6: BZOJ1016 && JSOI2008最小生成树计数

题目大意:

求一个图的最小生成树的个数。

算法讨论:

将边权从小到大SORT。然后对于相同边权的做一次处理进行缩点。如果缩点后出现多个联通块,有两种方法:对每个联通块做Matrix-Tree,然后相乘,或者在两个联通块加一个桥,这样方案数不会受影响。

坑点就是最后如果有形不成树的情况。

代码:

 #include <cstdlib>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector> using namespace std;
const int N = + ;
const int M = + ;
const int mod = ;
typedef long long ll; int n, m, tim, cnt;
ll A[N][N], ans = ;
int fa[N], lab[N], repos[N], f2[N]; struct Edge {
int u, v, d;
bool operator < (const Edge &k) const {
return d < k.d;
}
}e[M];
vector <Edge> p[N]; void Init() {
scanf("%d%d", &n, &m);
for(int i = ; i <= m; ++ i) {
scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].d);
}
} ll Det(ll a[N][N], int ns) {
ll res = ;
for(int i = ; i < ns; ++ i) {
for(int j = i + ; j < ns; ++ j) {
while(a[j][i]) {
ll t = a[i][i] / a[j][i];
for(int k = i; k < ns; ++ k)
a[i][k] = (a[i][k] - a[j][k] * t);
for(int k = i; k < ns; ++ k)
swap(a[i][k], a[j][k]);
res = -res;
}
}
if(a[i][i] == ) return ;
res = res * a[i][i];
}
return res;
} int find(int *f, int x) {
return f[x] == x ? x : (f[x] = find(f, f[x]));
} void Work(vector <Edge> &v) {
vector <Edge> :: iterator it;
int poi = ;
++ tim;
for(it = v.begin(); it != v.end(); ++ it) {
if(lab[fa[(*it).u]] != tim) {
lab[fa[(*it).u]] = tim;
repos[fa[(*it).u]] = ++ poi;
}
if(lab[fa[(*it).v]] != tim) {
lab[fa[(*it).v]] = tim;
repos[fa[(*it).v]] = ++ poi;
}
}
for(int i = ; i <= poi; ++ i)
for(int j = ; j <= poi; ++ j)
A[i][j] = ;
for(it = v.begin(); it != v.end(); ++ it) {
-- A[repos[fa[(*it).u]]][repos[fa[(*it).v]]];
-- A[repos[fa[(*it).v]]][repos[fa[(*it).u]]];
++ A[repos[fa[(*it).u]]][repos[fa[(*it).u]]];
++ A[repos[fa[(*it).v]]][repos[fa[(*it).v]]];
}
ans = ans * Det(A, poi) % mod;
} void Calc(int l, int r) {
for(int i = l; i <= r; ++ i) {
f2[fa[e[i].u]] = fa[e[i].u];
f2[fa[e[i].v]] = fa[e[i].v];
p[fa[e[i].u]].clear();
p[fa[e[i].v]].clear();
}
for(int i = l; i <= r; ++ i) {
f2[find(f2, fa[e[i].u])] = find(f2, fa[e[i].v]);
}
for(int i = l; i <= r; ++ i) {
if(fa[e[i].u] != fa[e[i].v]) {
p[find(f2, fa[e[i].u])].push_back(e[i]);
}
}
for(int i = l; i <= r; ++ i) {
if(!p[fa[e[i].u]].empty()) {
Work(p[fa[e[i].u]]), p[fa[e[i].u]].clear();
}
if(!p[fa[e[i].v]].empty()) {
Work(p[fa[e[i].v]]), p[fa[e[i].v]].clear();
}
}
} void Solve() {
sort(e + , e + m + );
cnt = n;
for(int i = ; i <= n; ++ i) fa[i] = i;
for(int i = ; i <= m && cnt > ;) {
int j = i;
for(; e[j].d == e[i].d && j <= m; ++ j) {
find(fa, e[j].u); find(fa, e[j].v);
}
Calc(i, j - );
for(int k = i; k < j; ++ k) {
int fx = find(fa, e[k].u), fy = find(fa, e[k].v);
if(fx != fy) {
fa[fx] = fy;
cnt --;
}
}
i = j;
}
if(cnt != ) ans = ;
printf("%lld\n", ans % mod);
} #define stone_eee
int main() {
#ifndef stone_
freopen("mst.in", "r", stdin);
freopen("mst.out", "w", stdout);
#endif Init();
Solve(); #ifndef stone_
fclose(stdin); fclose(stdout);
#endif
return ;
}

1016

基尔霍夫矩阵题目泛做(AD第二轮)的更多相关文章

  1. BZOJ 1002: [FJOI2007]轮状病毒【生成树的计数与基尔霍夫矩阵简单讲解+高精度】

    1002: [FJOI2007]轮状病毒 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 5577  Solved: 3031[Submit][Statu ...

  2. 【BZOJ】1002:轮状病毒(基尔霍夫矩阵【附公式推导】或打表)

    Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个N轮状基由圆环上N个不同的基原子和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道.如下图 ...

  3. 无向图生成树计数 基尔霍夫矩阵 SPOJ Highways

    基尔霍夫矩阵 https://blog.csdn.net/w4149/article/details/77387045 https://blog.csdn.net/qq_29963431/articl ...

  4. bzoj1002: [FJOI2007]轮状病毒(基尔霍夫矩阵)

    1002: [FJOI2007]轮状病毒 题目:传送门 题解: 决定开始板刷的第一题... 看到这题的时候想:这不就是求有多少种最小生成树的方式吗? 不会啊!!!%题解... 什么鬼?基尔霍夫矩阵?? ...

  5. bzoj 1002 [FJOI2007]轮状病毒 高精度&&找规律&&基尔霍夫矩阵

    1002: [FJOI2007]轮状病毒 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2234  Solved: 1227[Submit][Statu ...

  6. BZOJ1002 FJOI2007 轮状病毒 【基尔霍夫矩阵+高精度】

    BZOJ1002 FJOI2007 轮状病毒 Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个N轮状基由圆环上N个不同的基原子和圆心处一个核原子构成的,2个原 ...

  7. BZOJ 4031 HEOI2015 小Z的房间 基尔霍夫矩阵+行列式+高斯消元 (附带行列式小结)

    原题链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4031 Description 你突然有了一个大房子,房子里面有一些房间.事实上,你的房子可 ...

  8. bzoj 1002 找规律(基尔霍夫矩阵)

    网上说的是什么基尔霍夫矩阵,没学过这个,打个表找下规律,发现 w[i]=3*w[i-1]-w[i-2]+2; 然后写个高精直接递推就行了 //By BLADEVIL var n :longint; a ...

  9. [bzoj1002] [FJOI2007]轮状病毒轮状病毒(基尔霍夫矩阵)

    Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个N轮状基由圆环上N个不同的基原子 和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道.如下 ...

随机推荐

  1. POJ 1064 Cable master(二分查找+精度)(神坑题)

    POJ 1064 Cable master 一开始把 int C(double x) 里面写成了  int C(int x) ,莫名奇妙竟然过了样例,交了以后直接就wa. 后来发现又把二分查找的判断条 ...

  2. window下Slik SVN的安装配置

    我相信各位都应该对SVN不会陌生吧,我相信绝大多数人都使用过,但是并不是人人都自己配置过SVN服务器.下面就是我配置SVN服务器的步骤,以及在配置过程中碰见的一些问题,在此记录,希望对你有所帮助. 安 ...

  3. CSAPP--优化程序性能

    一.编写高效的程序: 1.选择合适的算法和数据结构. 2.编写出编译器能够有效优化以转换为高效可执行的源代码. 3.并行计算.当然重点还是第一个,良好的算法和数据结构大大减小了程序的时间复杂度. 二. ...

  4. Java虚拟机--虚拟机编译器

    void sspin() { short i; for (i = 0; i < 100; i++) { ; // Loop body is empty }} Method void sspin( ...

  5. swift闭包-备

    我给Swift 中的闭包一个定义:闭包是自包含的匿名函数代码块,可以作为表达式.函数参数和函数返回值,闭包表达式的运算结果是一种函数类型. Swift中的闭包类似于Objective-C中的代码块.J ...

  6. Qt创建和使用动态链接库

    一.创建共享库 1.新其他建项目,选择C++库 2.选择共享库,并取项目名称,单击下一步.这里取名位mylib 3.按默认配置单击下一步至模块选项,选择所需支持的模块.这里勾选Qtcore和QtGui ...

  7. 脱机BT transmission

    脱机BT transmission http://192.168.1.1:9091 也可以在使用Transmission Remote软件进行管理,如果下载太慢检查QoS 如果开了防火墙,需要打开默认 ...

  8. TCP/IP 中文译名为传输控制协议/因特网互联协议,又叫网络通讯协议

    原文地址:http://hi.baidu.com/albyuyrgqgbbhoq/item/65006d2d002ab33195f62ba1 TCP/IP(Transmission Control P ...

  9. FreeBsdb FAMP Lamp环境

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAA1IAAAHlCAIAAABwFFq0AAAgAElEQVR4nO3d23WruhYA0JTmciiGTm

  10. 能取悦生理期的女性吗?Le Parcel提供女性卫生用品按月订购服务,不是按包出售而是可以按片自由搭配 | 36氪

    能取悦生理期的女性吗?Le Parcel提供女性卫生用品按月订购服务,不是按包出售而是可以按片自由搭配 | 36氪 能取悦生理期的女性吗?Le Parcel提供女性卫生用品按月订购服务,不是按包出售而 ...