zoukankan      html  css  js  c++  java
  • 洛谷 P4100 [HEOI2013]钙铁锌硒维生素 解题报告

    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
    ",to[i]);
    	return 0;
    }
    

    2019.2.15

  • 相关阅读:
    rpm命令详解
    Linux基础提高_系统性能相关命令
    Day004_Linux基础命令之特殊符号与正则表达式通配符
    Linux基础_网站权限规划
    Day005_Linux基础之文件权限
    Day003_linux基础_系统启动过程及系统安装后优化
    win7旗舰版安装不了mysql问题-------win7系统版本选择问题的一点探索
    Java程序结构
    NCRE Java二级备考方案
    NCRE的JAVA二级考试大纲
  • 原文地址:https://www.cnblogs.com/butterflydew/p/10382777.html
Copyright © 2011-2022 走看看