[BZOJ3168][Heoi2013]钙铁锌硒维生素

[BZOJ3168] [Heoi2013]钙铁锌硒维生素

Description

银河队选手名单出来了!小林,作为特聘的营养师,将负责银河队选手参加宇宙比赛的饮食。众所周知,前往宇宙的某个星球,通常要花费好长好长的时间,人体情况在这之间会发生变化,因此,需要根据每天的情况搭配伙食,来保证营养。小林把人体需要的营养分成了n种,这些营养包括但不限于铁,钙。他准备了2套厨师机器人,一套厨师机器人有n个,每个厨师机器人只会做一道菜,这道菜一斤能提供第i种营养xi微克。想要吃这道菜的时候,只要输入一个数,就能吃到对应数量的这道菜了。为防止摄入过量对身体造成的伤害,每个机器人还有防过量摄入药,只要输入一个数,就能生成一定剂量的药,吃了这些药,就能减少相当于食用对应数目的这道菜提供的营养。小林之所以准备2套厨师机器人,正是因为旅途漫漫,难以预计,也许某一个厨师机器人在途中坏掉,要是影响了银河队选手的身体,就不好了。因此,第2套厨师机器人被用来做第1套的备用。小林需要为每一个第1套厨师机器人选一个第2套厨师机器人作备份,使得当这个机器人坏掉时,用备份顶替,整套厨师机器人仍然能搭配出任何营养需求,而且,每个第2套厨师机器人只能当一个第1套厨师机器人的备份。

Input

第一行包含一个正整数n。接下来n行,每行n个整数,表示第1套厨师机器人做的菜每一斤提供的每种营养。再接下来n行,每行n个整数,表示第2套厨师机器人做的菜每一斤提供的每种营养。1≤n≤300,所有出现的整数均非负,且不超过10,000。

Output

第一行是一个字符串,如果无法完成任务,输出“NIE”,否则输出“TAK”并跟着n行,第i行表示第i个第1套机器人的备份是哪一个第2套机器人。为了避免麻烦,如果有多种可能的答案,请给出字典序最小的那一组。

Sample Input

3
1 0 0
0 1 0
0 0 1
2 3 0
0 7 8
0 0 9

Sample Output

TAK
1
2
3

试题分析

推荐博客:Link
首先A中的N个向量可以表示出N种营养,所以A中的向量是线性无关的。
那么也就是要求B替换A后仍旧线性无关。
那么只需要求\(B_i=\sum c_j A_j\),那么如果\(c_j\)是0,说明不用\(A_j\)就可以表出\(B_i\),所以\(A_j\)是不能被\(B_j\)替换的,反之亦然。
说明存在矩阵\(C\)满足:

\[\begin{pmatrix} c_{1,1} & c_{1,2} & c_{1,3} & \cdots & c_{1,n} \\ c_{2,1} & c_{2,2} & c_{2,3} & \cdots & c_{2,n} \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ c_{n,1} & c_{n,2} & c_{n,3} & \cdots & c_{n,n} \\ \end{pmatrix} \times \begin{pmatrix} A_1\\A_2\\\vdots \\A_n\\ \end{pmatrix}= \begin{pmatrix} B_1\\B_2\\\vdots \\B_n\\ \end{pmatrix}\]

于是求出\(A\)的逆矩阵就可以建立二分图并贪心匹配了。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<algorithm>
 
using namespace std;
#define LL long long
 
inline int read(){
    int x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int INF = 2147483600;
const int MAXN = 100010;
const int Mod = 999911657;
 
int N; bool Nxt[501][501];
bool vis[501]; int fa[MAXN+1];
 
inline LL Pow(LL A,LL B){
    LL res=1;
    while(B){
        if(B&1) res=res*A%Mod;
        A=A*A%Mod; B>>=1;
    } return res;
}
struct Matrix{
    int A[301][301]; int x,y;
    inline void init(int xx,int yy){
        memset(A,0,sizeof(A));
        x=xx; y=yy;
    }
    inline Matrix Get_Inv(){
        Matrix Inv;  Inv.init(x,y);
        for(int i=1;i<=x;i++) Inv.A[i][i]=1;
        for(int i=1;i<=x;i++){
            int r=i;
            for(int j=i;j<=x;j++)
                if(A[j][i]) {r=j; break;}
            if(i!=r) for(int j=1;j<=y;j++){
                swap(A[i][j],A[r][j]);
                swap(Inv.A[i][j],Inv.A[r][j]);
            } LL inv=Pow(A[i][i],Mod-2); for(int j=1;j<=y;j++){
                A[i][j]=1LL*A[i][j]*inv%Mod;
                Inv.A[i][j]=1LL*Inv.A[i][j]*inv%Mod;
            } for(int j=1;j<=x;j++){
                if(j==i) continue;
                LL tp=(Mod-A[j][i])%Mod;
                for(int k=1;k<=y;k++){
                    (A[j][k]+=1LL*tp*A[i][k]%Mod)%=Mod;
                    (Inv.A[j][k]+=1LL*tp*Inv.A[i][k]%Mod)%=Mod;
                }
            }
        } return Inv;
    }
    inline void Get(int xx,int yy){
        init(xx,yy);
        for(int i=1;i<=xx;i++){
            for(int j=1;j<=yy;j++)
                A[i][j]=read();
        } return ;
    }
}A,B,C;
Matrix operator * (Matrix A,Matrix B){
    Matrix C; if(A.x==B.y&&A.y!=B.x) swap(A,B);
    C.init(A.x,B.y);
    for(int i=1;i<=A.x;i++){
        for(int j=1;j<=B.y;j++)
            for(int k=1;k<=A.y;k++)
                (C.A[i][j]+=1LL*A.A[i][k]*B.A[k][j]%Mod)%=Mod;
    } return C;
}
inline bool DFS(int k){
    for(int i=1;i<=N;i++){
        if(Nxt[k][i]&&!vis[i]){
            vis[i]=true;
            if(!fa[i]||DFS(fa[i])){
                fa[i]=k; return true;
            }
        }
    } return false;
}
inline bool DFS2(int k,int Fa){
    for(int i=1;i<=N;i++){
        if(Nxt[k][i]&&!vis[i]){
            vis[i]=true;
            if(fa[i]==Fa || fa[i]>Fa && DFS2(fa[i],Fa)){
                fa[i]=k; return true;
            }
        }
    } return false;
}
 
int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    N=read(); A.Get(N,N),B.Get(N,N);
    Matrix Inv=(A.Get_Inv());
    C=B*Inv;
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++) Nxt[i][j]=(bool)C.A[j][i];
    }
    for(int i=1;i<=N;i++){
        memset(vis,false,sizeof(vis));
        if(!DFS(i)){puts("NIE"); return 0;}
    } puts("TAK");
    for(int i=1;i<=N;i++){
        memset(vis,false,sizeof(vis));
        DFS2(i,i);
    }
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++){
            if(fa[j]==i)
                printf("%d\n",j);
        }
    }
    return 0;
}
posted @ 2018-08-27 12:26  wxjor  阅读(168)  评论(0编辑  收藏  举报