二分图+矩阵求逆

既然我们考虑b能替换哪些a,那么我们自然要得出b被哪些a表示,这里我们设一个矩阵C,那么C*A = B

为什么呢?直接A*C = B是不可行的,因为都是行向量,不能直接乘,那么我们转置一下,得出At*C=Bt,这样就很科学了,那么再转回来,A*Ct=B,于是Ct=B*A^-1那么矩阵求逆就能得出Ct,于是我们再转置回来就能得出B是由哪些A表示的,然后跑二分图匹配就行了。

二分图匹配理解的不是很清楚,大概是不能用之前已经用过较小的编号来更新自己,还是看CQzhangyu的吧。

矩阵求逆用取模就行了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = ;
const ll P = ;
int rd()
{
int x = , f = ; char c = getchar();
while(c < '' || c > '') { if(c == '-') f = -; c = getchar(); }
while(c >= '' && c <= '') { x = x * + c - ''; c = getchar(); }
return x * f;
}
ll power(ll x, ll t)
{
ll ret = ;
for(; t; t >>= , x = x * x % P)
if(t & )
ret = ret * x % P;
return ret;
}
void up(ll &x, const ll &t)
{
x = ((x + t) % P + P) % P;
}
int n;
int vis[N], Map[N][N], match[N];
struct Matrix {
ll a[N][N];
Matrix() { memset(a, , sizeof(a)); }
void set() { for(int i = ; i <= n; ++i) a[i][i] = ; }
Matrix friend operator * (const Matrix &a, const Matrix &b) {
Matrix ret;
for(int i = ; i <= n; ++i)
for(int k = ; k <= n; ++k) if(a.a[i][k])
for(int j = ; j <= n; ++j)
up(ret.a[i][j], a.a[i][k] * b.a[k][j] % P);
return ret;
}
Matrix Inverse()
{
Matrix c;
c.set();
for(int i = ; i <= n; ++i)
{
int now = i;
while(now <= n && !a[now][i]) ++now;
for(int j = ; j <= n; ++j)
{
swap(a[now][j], a[i][j]);
swap(c.a[now][j], c.a[i][j]);
}
ll Inv = power(a[i][i], P - );
for(int j = ; j <= n; ++j)
{
a[i][j] = a[i][j] * Inv % P;
c.a[i][j] = c.a[i][j] * Inv % P;
}
for(int k = ; k <= n; ++k) if(k != i)
{
ll t = ((P - a[k][i] % P) % P + P) % P;
for(int j = ; j <= n; ++j)
{
a[k][j] = ((a[k][j] + t * a[i][j] % P) % P + P) % P;
c.a[k][j] = ((c.a[k][j] + t * c.a[i][j] % P) % P + P) % P;
}
}
}
return c;
}
void print()
{
for(int i = ; i <= n; ++i)
{
for(int j = ; j <= n; ++j) printf("%d ", a[i][j]);
puts("");
}
}
} a, b, c, d;
bool dfs(int u)
{
for(int i = ; i <= n; ++i) if(!vis[i] && Map[u][i])
{
vis[i] = ;
if(!match[i] || dfs(match[i]))
{
match[i] = u;
return true;
}
}
return false;
}
bool dfs(int u, int lev)
{
for(int i = ; i <= n; ++i) if(!vis[i] && Map[u][i])
{
vis[i] = ;
if(match[i] == lev || (match[i] > lev && dfs(match[i], lev)))
{
match[i] = u;
return true;
}
}
return false;
}
int main()
{
// freopen("ferrous.in", "r", stdin);
// freopen("ferrous.out", "w", stdout);
n = rd();
for(int i = ; i <= n; ++i)
for(int j = ; j <= n; ++j)
a.a[i][j] = rd();
for(int i = ; i <= n; ++i)
for(int j = ; j <= n; ++j)
b.a[i][j] = rd();
c = b * a.Inverse();
for(int i = ; i <= n; ++i)
for(int j = ; j <= n; ++j) if(c.a[i][j])
Map[j][i] = ;
int ans = ;
for(int i = ; i <= n; ++i)
{
memset(vis, , sizeof(vis));
ans += dfs(i);
}
if(ans < n)
{
puts("NIE");
return ;
}
for(int i = ; i <= n; ++i)
{
memset(vis, , sizeof(vis));
dfs(i, i);
}
puts("TAK");
for(int i = ; i <= n; ++i)
for(int j = ; j <= n; ++j) if(match[j] == i)
printf("%d\n", j);
// fclose(stdin);
// fclose(stdout);
return ;
}

bzoj3168的更多相关文章

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

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

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

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

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

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

  4. BZOJ3168. [HEOI2013]钙铁锌硒维生素(线性代数+二分图匹配)

    题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=3168 题解 首先,我们需要求出对于任意的 \(i, j(1 \leq i, j \leq ...

随机推荐

  1. Cent OS下发送邮件

    首先安装发送邮件的服务: yum install -y sendmail 安装完成之后在安装mutt yum install -y mutt 安装完成之后我们就可以发送邮件了 mutt     tes ...

  2. Libx264 编码错误 Input picture width(320) is greater than stride (0)

    Ffmpeg libx264编码出现 Input picture width(320) is greater than stride (0),问题出在视频格式不正确. libx264 编码要求输入源的 ...

  3. Java反射及其在Android中的应用学习总结

    一. Java反射机制 Reflection 是Java被视为动态(或准动态)语言的一个关键性质.这个机制同意程序在执行时透过Reflection APIs取得不论什么一个已知名称的class的内部信 ...

  4. leetcode第一刷_Symmetric Tree

    必须承认,一開始这道题我是不会做的.由于我心目中的树遍历仅仅能用一个节点发起.多么天真而无知. 我想不通如何同一时候遍历两颗子树.由于根节点一定是一个啊.但是,作为对称轴上的它.从一開始就不应该被考虑 ...

  5. C# winform ListView 的右键菜单的下级菜单的选项视情况禁用方法

    ListView 和右键菜单例如以下图: 要实现功能是: 1.用户状态为[活动]时,改动用户状态为[活动]禁用,反之则反. 2.而且仅仅实用户状态为[非活动]时,[删除学员用户]才是可用状态. 功能非 ...

  6. angularJS contenteditable 指令双向绑定

    项目遇到需求有点奇葩:双击div使其可编辑,失去焦点后进行数据绑定 通过自定义指令完成 好了上代码: .directive('contentEditable', function() { return ...

  7. Kristen Grauman

    http://www.cs.utexas.edu/~grauman/ CV         Publications         Code           Data        Short ...

  8. g++ 6.4编译opencv-2.4.10报错记录

      fetch公司的项目进行编译,此项目依赖opencv库.由于本人一直比较偏爱fedora,但也因此给我带来了许多"乐趣"(麻烦).fedora一直走得比较前沿,g++ 6.3了 ...

  9. LeetCode215:Kth Largest Element in an Array

    Find the kth largest element in an unsorted array. Note that it is the kth largest element in the so ...

  10. iOS菜鸟学习--怎样避免两个button同一时候响应

    在測试应用时.有时会变态的将两个UIButton同一时候按住来測试.结果就是两个button会同一时候响应,会出现同一时候push两个viewcontroller等非正常情况.为了避免用户误操作造成这 ...