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

2019.2.15

posted @ 2019-02-15 11:37  露迭月  阅读(166)  评论(0编辑  收藏  举报