bzoj3168
二分图+矩阵求逆
既然我们考虑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的更多相关文章
- 【BZOJ3168】[Heoi2013]钙铁锌硒维生素 高斯消元求矩阵的逆+匈牙利算法
[BZOJ3168][Heoi2013]钙铁锌硒维生素 Description 银河队选手名单出来了!小林,作为特聘的营养师,将负责银河队选手参加宇宙比赛的饮食.众所周知,前往宇宙的某个星球,通常要花 ...
- BZOJ3168: [Heoi2013]钙铁锌硒维生素
设$A^TC=B^T$,这样$C_{ij}$表示$B_j$的线性表出需要$A_i$,那么$B_j$可以替换$A_i$,根据$C=(A^T)^{-1}B^T$求出$C$.要求字典序最小完美匹配,先求任意 ...
- bzoj3168 钙铁锌硒维生素 (矩阵求逆+二分图最小字典序匹配)
设第一套为A,第二套为B 先对于每个B[i]判断他能否替代A[j],即B[i]与其他的A线性无关 设$B[i]=\sum\limits_{k}{c[k]*A[k]}$,那么只要看c[j]是否等于零即可 ...
- BZOJ3168. [HEOI2013]钙铁锌硒维生素(线性代数+二分图匹配)
题目链接 https://www.lydsy.com/JudgeOnline/problem.php?id=3168 题解 首先,我们需要求出对于任意的 \(i, j(1 \leq i, j \leq ...
随机推荐
- HDU 4514并查集判环+最长路
点击打开链接 题意:中文题...... 思路:先推断是否能成环,之前以为是有向图,就用了spfa推断,果断过不了自己出的例子,发现是无向图.并查集把,两个点有公共的父节点,那就是成环了,之后便是求最长 ...
- 转 Python Selenium设计模式-POM
前言 本文就python selenium自动化测试实践中所需要的POM设计模式进行分享,以便大家在实践中对POM的特点.应用场景和核心思想有一定的理解和掌握. 为什么要用POM 基于python s ...
- 笔记11 export to excel
参考两篇博客:http://blog.csdn.net/zyming0815/article/details/5939104 http://blog.csdn.net/g710710/article/ ...
- initializer_list、初始化列表、列表初始化
什么是列表初始化 使用一个花括号来初始化变量,表现形式如下: std::vector<int>a{1,2,3,4,5}; 或者 std::vector<int>a = {1,2 ...
- Unity光滑与粗糙的材质——相似于生锈的金属表面
纹理是在Photoshop中制作的,终于效果则是在Unity里得到的.这样的类型的材质.在3D游戏中非经常见.
- Kristen Grauman
http://www.cs.utexas.edu/~grauman/ CV Publications Code Data Short ...
- input 的read only 和 disable的区别
read only ---------->只能读,不能操作,但是数据可以提交 disable -------------->控件被禁用,数据不能提交
- sql中in/not in 和exists/not exists的使用方法差别
1:首先来说in/not in的使用方法 in/not in是确定单个属性的值是否和给定的值或子查询的值相匹配: select * from Student s where s.id in(1,2,3 ...
- JavaScript根据Json数据来做的模糊查询功能
类似于百度搜索框的模糊查找功能 需要有有已知数据,实现搜索框输入字符,然后Js进行匹配,然后可以通过鼠标点击显示的内容,把内容显示在搜索框中 当然了,正则只是很简单的字符匹配,不具备多么复杂的判断 & ...
- VMware虚拟机下实现Linux与window文件夹共享
这里说的是在VMware虚拟机下来实现在windows与Linux下共享一个文件夹. 下面来说明一下是如何实现的: 1.安装VMware.Workstation. 2.安装Fedora10. 3.完成 ...