P4100 [HEOI2013]钙铁锌硒维生素
题目描述
银河队选手名单出来了!小林,作为特聘的营养师,将负责银河队选手参加 宇宙比赛的饮食。
众所周知,前往宇宙的某个星球,通常要花费好长好长的时间,人体情况在 这之间会发生变化,因此,需要根据每天的情况搭配伙食,来保证营养。
小林把人体需要的营养分成了 \(n\) 种,这些营养包括但不限于铁,钙。他准备 了 \(2\) 套厨师机器人,一套厨师机器人有 \(n\) 个,每个厨师机器人只会做一道菜,这道菜一斤能提供第 \(i\) 种营养 \(x_i\) 微克。想要吃这道菜的时候,只要输入一个数,就能吃到对应数量的这道菜了。为防止摄入过量对身体造成的伤害,每个机器人还 有防过量摄入药,只要输入一个数,就能生成一定剂量的药,吃了这些药,就能减少相当于食用对应数目的这道菜提供的营养。
小林之所以准备 \(2\) 套厨师机器人,正是因为旅途漫漫,难以预计,也许某一 个厨师机器人在途中坏掉,要是影响了银河队选手的身体,就不好了。因此,第 \(2\) 套厨师机器人被用来做第 \(1\) 套的备用。小林需要为每一个第 \(1\) 套厨师机器人选 一个第 \(2\) 套厨师机器人作备份,使得当这个机器人坏掉时,用备份顶替,整套厨 师机器人仍然能搭配出任何营养需求,而且,每个第 \(2\) 套厨师机器人只能当一个 第 \(1\) 套厨师机器人的备份。
输入输出格式
输入格式:
输入文件的第一行包含一个正整数 \(n\)。
接下来 \(n\) 行,每行 \(n\) 个整数,表示第 \(1\) 套厨师机器人做的菜每一斤提供的每种营养。
再接下来 \(n\) 行,每行 \(n\) 个整数, 表示第 \(2\) 套厨师机器人做的菜每一斤提供的每种营养。
输出格式:
输出文件的第一行是一个字符串,如果无法完成任务,输出“\(NIE\)”,否则输 出“\(TAK\)”,并跟着 \(n\) 行,第 \(i\) 行表示第 \(i\) 个第 \(1\) 套机器人的备份是哪一个第 \(2\) 套机器人。为了避免麻烦,如果有多种可能的答案,请给出字典序最小的那一组。
说明
对于\(10\%\)的数据,\(n = 2\);
对于\(20\%\)的数据,\(n ≤ 10\);
对于\(40\%\)的数据,\(n ≤ 30\);
对于\(60\%\)的数据,\(n ≤ 50\);
对于\(80\%\)的数据,\(n ≤ 100\);
对于\(100\%\)的数据,\(1 ≤ n ≤ 300\),所有出现的整数均非负,且不超过 \(10,000\)。
好题阿
首先\(n\)个\(A\)向量得是向量无关的
然后每个\(B\)向量一定可以被\(A\)向量作为基底表示出来,即\(B=\sum c_iA_i\),若\(c_i\)不为\(0\),就说明这个\(B\)必须要\(A_i\)才能被表示,说明去掉这个\(A_i\)后\(B\)与其他\(A\)线性无关,即可以换掉这个\(A\)。
那么\(C*A=B\),矩阵求个逆把\(C\)搞出来,我们就可以确定替换关系,然后进行二分图匹配。
这时候不一定字典序最小,我们再随便跑跑匹配改一改跑一个最小就可以了。
Code:
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
const int mod=998244353;
const int N=602;
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
#define mul(x,y) (1ll*(x)*(y)%mod)
int qp(int d,int k){int f=1;while(k){if(k&1)f=mul(f,d);d=mul(d,d),k>>=1;}return f;}
int read()
{
int x=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
return x;
}
int a[N][N],b[N][N],yuu[N][N],yuy[N][N],n;
bool Matrixinv()
{
for(int i=1;i<=n;i++) a[i][i+n]=1;
for(int i=1;i<=n;i++)
{
int id=-1;
for(int j=i;j<=n;j++) if(a[j][i]) {id=j;break;}
if(id==-1) return false;
std::swap(a[i],a[id]);
int inv=qp(a[i][i],mod-2);
for(int j=n<<1;j>=i;j--) a[i][j]=mul(a[i][j],inv);
for(int j=i+1;j<=n;j++)
for(int k=n<<1;k>=i;k--)
a[j][k]=add(a[j][k],mod-mul(a[j][i],a[i][k]));
}
for(int i=n;i;i--)
for(int j=i-1;j;j--)
for(int k=n<<1;k>=i;k--)
a[j][k]=add(a[j][k],mod-mul(a[j][i],a[i][k]));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j]=a[i][j+n];
return true;
}
int used[N],mat[N],to[N],ban[N];
bool dfs(int now)
{
for(int i=1;i<=n;i++)
if(yuy[now][i]&&!used[i]&&!ban[i])
{
used[i]=1;
if(!mat[i]||dfs(mat[i]))
{
mat[i]=now;
to[now]=i;
return true;
}
}
return false;
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j]=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
b[i][j]=read();
if(!Matrixinv()) return puts("NIE"),0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
yuu[i][j]=add(yuu[i][j],mul(b[i][k],a[k][j]));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(yuu[i][j])
yuy[j][i]=1;
for(int i=1;i<=n;i++)
{
memset(used,0,sizeof used);
if(!dfs(i)) return puts("NIE"),0;
}
puts("TAK");
int tto[N],tmat[N];
for(int i=1;i<=n;i++)
{
memset(used,0,sizeof used);
for(int j=1;j<=n;j++) tto[j]=to[j],tmat[j]=mat[j];
int bee=to[i],flag=0;mat[bee]=0;
for(int j=1;j<bee;j++)
if(yuy[i][j]&&!ban[j]&&!used[j])
{
used[j]=1;
if(!ban[j]&&dfs(mat[j]))
{
to[i]=j,mat[j]=i;
flag=1;break;
}
}
if(!flag) for(int j=1;j<=n;j++) to[j]=tto[j],mat[j]=tmat[j];
ban[to[i]]=1;
}
for(int i=1;i<=n;i++) printf("%d\n",to[i]);
return 0;
}
2019.2.15