题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=3168

题解

首先,我们需要求出对于任意的 \(i, j(1 \leq i, j \leq n)\),第二套中的第 \(j\) 个机器人是否可以替换第一套中的第 \(i\) 个机器人。

将第 \(i\) 个机器人提供的第 \(j\) 种营养的量记为 \(a_{i, j}\),我们可以得到一个 \(n \times n\) 的矩阵 \(A\)。那么,整套机器人能搭配出任何营养需求等价于将矩阵 \(A\) 化为行阶梯形矩阵后拥有 \(n\) 个非零行,即该矩阵为满秩矩阵。

由于满秩矩阵即可逆矩阵,矩阵 \(A\) 可逆等价于矩阵 \(A\) 的行列式值 \(|A| \neq 0\),因此,我们的任务是快速求出矩阵 \(A\) 在替换了某一行的元素后的行列式的值。不难想到通过行列式按行展开法则来计算行列式的值,即假如替换的是矩阵 \(A\) 的第 \(i\) 行,那么有(以下用 \(A_{i, j}\) 表示矩阵的 \((i, j)\) 元的代数余子式,矩阵的行列标号为 \(1 \sim n\)):

\[|A| = \sum_\limits{k = 1}^{n} a_{i, k}A_{i, k}
\]

其中的 \(a_{i, k}(1 \leq k \leq n)\) 为第 \(i\) 行替换后的元素值。由于代数余子式 \(A_{i, k}\) 的值与第 \(i\) 行本身的元素无关,因此我们可以先用 \(O(n^3)\) 的时间求出矩阵 \(A\) 的伴随矩阵,从而得到矩阵所有元素对应的代数余子式的值。具体地,设矩阵 \(A\) 的伴随矩阵为 \(A^*\),根据 \(A^{-1} = \frac{1}{|A|}A^*\) 可得 \(A^* = |A|A^{-1}\),由于可以在 \(O(n^3)\) 的时间内求出矩阵 \(A\) 的逆矩阵 \(A^{-1}\)(并顺便求出矩阵 \(A\) 的行列式值 \(|A|\)),因此自然能够在相同的时间内求出伴随矩阵。得到所有元素的代数余子式的值后,我们便能在 \(O(n)\) 的时间内求出单次行替换后矩阵的行列式值。一共需要进行 \(O(n^2)\) 次替换与判断,故预处理出每个机器人对应的替换集合所需的总时间复杂度为 \(O(n^3)\)。

预处理完毕后,我们就可以通过求二分图匹配来寻找解的方案。不过,注意到题目要求求出字典序最小的匹配,因此直接通过一次二分图匹配得到的方案并不是我们所需要的答案,我们需要在此基础上再进行一次贪心。具体地,我们从小到大枚举编号 \(i\),然后判断在第一套机器人中编号小于 \(i\) 的机器人的匹配状态不变的情况下,编号为 \(i\) 的机器人能否与编号更优的机器人匹配即可。

总时间复杂度为 \(O(n^3)\)。

代码

#include<bits/stdc++.h>

using namespace std;

const int N = 3e2 + 10, mod = 1e9 + 7;

void add(int& x, int y) {
x += y;
if (x >= mod) {
x -= mod;
}
} int mul(int x, int y) {
return (long long) x * y % mod;
} int qpow(int v, int p) {
int result = 1;
for (; p; p >>= 1, v = mul(v, v)) {
if (p & 1) {
result = mul(result, v);
}
}
return result;
} int n, a[N][N], b[N][N], inv[N][N], adj[N][N], choice[N], visit[N], tt, answer[N];
vector<int> go[N]; void transform1(int a[N][N], int i, int j) {
for (int p = 0; p < n; ++p) {
swap(a[i][p], a[j][p]);
}
} void transform2(int a[N][N], int i, int k) {
for (int p = 0; p < n; ++p) {
a[i][p] = mul(a[i][p], k);
}
} void transform3(int a[N][N], int i, int j, int k) {
for (int p = 0; p < n; ++p) {
add(a[i][p], mul(a[j][p], k));
}
} void get_adj() {
int det = 1;
for (int i = 0; i < n; ++i) {
inv[i][i] = 1;
}
for (int i = 0; i < n; ++i) {
if (!a[i][i]) {
int p = i;
for (int j = i + 1; j < n; ++j) {
if (a[j][i]) {
p = j;
}
}
if (p == i) {
puts("NIE");
exit(0);
}
transform1(a, i, p);
transform1(inv, i, p);
det = (mod - det) % mod;
}
det = mul(det, a[i][i]);
int x = qpow(a[i][i], mod - 2);
transform2(a, i, x);
transform2(inv, i, x);
for (int j = i + 1; j < n; ++j) {
int p = a[j][i];
transform3(a, j, i, (mod - p) % mod);
transform3(inv, j, i, (mod - p) % mod);
}
}
for (int i = n - 1; ~i; --i) {
for (int j = i + 1; j < n; ++j) {
int p = a[i][j];
transform3(a, i, j, (mod - p) % mod);
transform3(inv, i, j, (mod - p) % mod);
}
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
adj[i][j] = mul(inv[j][i], det);
}
}
} bool find(int u) {
for (int i = 0; i < go[u].size(); ++i) {
int v = go[u][i];
if (visit[v] != tt) {
visit[v] = tt;
if (!~choice[v] || find(choice[v])) {
choice[v] = u;
return true;
}
}
}
return false;
} bool find_better(int u, int down) {
for (int i = 0; i < go[u].size(); ++i) {
int v = go[u][i];
if (visit[v] != tt) {
visit[v] = tt;
if (choice[v] == down || (choice[v] > down && find_better(choice[v], down))) {
answer[u] = v;
choice[v] = u;
return true;
}
}
}
return false;
} int main() {
scanf("%d", &n);
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
scanf("%d", &a[i][j]);
}
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
scanf("%d", &b[i][j]);
}
}
get_adj();
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
int det = 0;
for (int k = 0; k < n; ++k) {
add(det, mul(b[j][k], adj[i][k]));
}
if (det) {
go[i].push_back(j);
}
}
}
memset(choice, -1, sizeof choice);
int total = 0;
for (int i = 0; i < n; ++i) {
++tt;
total += find(i);
}
if (total != n) {
puts("NIE");
} else {
puts("TAK");
for (int i = 0; i < n; ++i) {
++tt;
find_better(i, i);
printf("%d\n", answer[i] + 1);
}
}
return 0;
}

BZOJ3168. [HEOI2013]钙铁锌硒维生素(线性代数+二分图匹配)的更多相关文章

  1. BZOJ3168: [Heoi2013]钙铁锌硒维生素

    设$A^TC=B^T$,这样$C_{ij}$表示$B_j$的线性表出需要$A_i$,那么$B_j$可以替换$A_i$,根据$C=(A^T)^{-1}B^T$求出$C$.要求字典序最小完美匹配,先求任意 ...

  2. 【BZOJ3168】[Heoi2013]钙铁锌硒维生素 高斯消元求矩阵的逆+匈牙利算法

    [BZOJ3168][Heoi2013]钙铁锌硒维生素 Description 银河队选手名单出来了!小林,作为特聘的营养师,将负责银河队选手参加宇宙比赛的饮食.众所周知,前往宇宙的某个星球,通常要花 ...

  3. BZOJ 3168: [Heoi2013]钙铁锌硒维生素 [线性基 Hungary 矩阵求逆]

    3168: [Heoi2013]钙铁锌硒维生素 题意:给一个线性无关组A,再给一个B,要为A中每个向量在B中选一个可以代替的向量,替换后仍然线性无关.判断可行和求字典序最小的解 PoPoQQQ orz ...

  4. 洛谷 P4100 [HEOI2013]钙铁锌硒维生素 解题报告

    P4100 [HEOI2013]钙铁锌硒维生素 题目描述 银河队选手名单出来了!小林,作为特聘的营养师,将负责银河队选手参加 宇宙比赛的饮食. 众所周知,前往宇宙的某个星球,通常要花费好长好长的时间, ...

  5. 【BZOJ】3168: [Heoi2013]钙铁锌硒维生素

    题解 Ca Fe Zn Se 显然我们既然初始矩阵就能通过线性变换变成单位矩阵,则该矩阵一定有逆 没有逆输出NIE 而且因为这些向量两两正交,则表示一个向量的时候表示方法唯一 那么我们求一个逆可以求出 ...

  6. BZOJ 3168 Luogu P4100 [HEOI2013]钙铁锌硒维生素 (矩阵求逆、二分图匹配)

    线性代数+图论好题. 题目链接: (bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=3168 (luogu) https://www.lu ...

  7. bzoj3168 钙铁锌硒维生素 (矩阵求逆+二分图最小字典序匹配)

    设第一套为A,第二套为B 先对于每个B[i]判断他能否替代A[j],即B[i]与其他的A线性无关 设$B[i]=\sum\limits_{k}{c[k]*A[k]}$,那么只要看c[j]是否等于零即可 ...

  8. BZOJ 3168 Heoi2013 钙铁锌硒维生素 矩阵求逆+匈牙利算法

    题目大意:给定一个n∗n的满秩矩阵A和一个n∗n的矩阵B.求一个字典序最小的1...n的排列a满足将随意一个Ai换成Bai后矩阵A仍然满秩 我们考虑建立一个二分图.假设Ai能换成Bj.就在i−> ...

  9. BZOJ 3168 [Heoi2013]钙铁锌硒维生素 ——矩阵乘法 矩阵求逆

    考虑向量ai能否换成向量bj 首先ai都是线性无关的,然后可以a线性表出bj c1*a1+c2*a2+...=bj 然后移项,得 c1/ci*a1+...-1/ci*bj+...=ai 所以当ci不为 ...

随机推荐

  1. C语言基础课First作业

    一.大学和高中最大的不同是没有人天天看着你,也不会担心上课的时候班主任在后门偷偷瞄着我们,通过阅读邹欣老师的博客后,心目中理想的师生关系就是Coach/Trainee(健身教练/健身学员)的关系,想到 ...

  2. JavaScript 语法总结3

    1. 数组初始化可以跳着来  var s = [1,2,,,,6]; // 中间省略的元素为undefined 2. 函数定义表达式:  var f = function(args){ return ...

  3. iOS密码输入框的实现

    [iOS密码输入框的实现] 就是一个UITextField,把属性 UITextField.secureTextEntry设置为Yes即可.此种UI效果为iOS默认效果.

  4. Workflow笔记2——状态机工作流(转)

    出处:http://www.cnblogs.com/jiekzou/p/6192813.html 在上一节Workflow笔记1——工作流介绍中,介绍的是流程图工作流,后来微软又推出了状态机工作流,它 ...

  5. Docker 基本原理

    1 什么是Docker? Docker是基于Go语言实现的云开源项目.Docker的主要目标是“Build,Ship and Run Any App,Anywhere”,也就是通过对应用组件的封装.分 ...

  6. poj2115 Looooops 扩展欧几里德的应用

    好开心又做出一道,看样子做数论一定要先看书,认认真真仔仔细细的看一下各种重要的性质 及其用途,然后第一次接触的题目 边想边看别人的怎么做的,这样做出第一道题目后,后面的题目就完全可以自己思考啦 设要+ ...

  7. HDU1412:{A} + {B}

    Problem Description 给你两个集合,要求{A} + {B}. 注:同一个集合中不会有两个相同的元素.   Input 每组输入数据分为三行,第一行有两个数字n,m(0<n,m& ...

  8. 数据集和JSON相互转换

    使用DELPHI原生类实现数据集和JSON相互转换  JSON二要素:数组和对象.对象可以包含数组,数组可以包含对象.无层数限制.OLEVARIANT也类似,OLEVARIANT的一个元素又可以是OL ...

  9. AngularJS Backbone.js Ember.js 对比

    看到一篇关于AngularJS Backbone Ember.js的对比,建议看一看 说说个人的观点(本人学艺不精,只是个人的观点,不保证观点完全正确,请轻拍): backbone.js 短小精悍,非 ...

  10. C# 使用ProcessStartInfo调用exe获取不到重定向数据的解决方案

    emmmmm,最近在研究WFDB工具箱,C语言写的,无奈本人C语言功底不够,只想直接拿来用,于是打算通过ProcessStartInfo来调取编译出来的exe程序获取输出. 一开始就打算偷懒,从园子里 ...