zoukankan      html  css  js  c++  java
  • [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)满足:

    [egin{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} imes egin{pmatrix} A_1\A_2\vdots \A_n\ end{pmatrix}= egin{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
    ",j);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    02-Java 数组和排序算法
    Spring Security 入门
    mysql外键理解
    redis能否对set数据的每个member设置过期时间
    Redis sortedset实现元素自动过期
    mysql之触发器trigger
    一篇很棒的 MySQL 触发器学习教程
    mysql触发器
    云游戏
    mysql触发器个人实战
  • 原文地址:https://www.cnblogs.com/wxjor/p/9541514.html
Copyright © 2011-2022 走看看