码迷,mamicode.com
首页 > 其他好文 > 详细

[JLOI2015]装备购买

时间:2020-04-21 09:42:52      阅读:60      评论:0      收藏:0      [点我收藏+]

标签:exist   strong   struct   常用   equal   http   cst   max   spawn   

题目

??点这里看题目。

分析

??可以发现,一组装备可以同时购买的条件是这组装备线性无关
??首先不难发现一个拟阵\(M=<S,I>\),其中:
??\(S\)为装备的集合;如果\(A\subseteq S\),那么\(A\in I\)当且仅当\(A\)内的元素线性无关。
??显然\(M\)是一个子集系统,考虑一下它的交换性:
??对于\(A,B\in I\),如果\(|A|<|B|\),我们需要证明\(\exists x\in B-A, A\cup \{x\}\in I\),即新的集合仍然线性无关。
??考虑反证法,即假设不存在这样的\(x\)。这意味着\(\forall x\in B-A\)\(x\)都可以在\(A\)中表示出来。那么\(B\)中的元素都可以在\(A\)中表示出来。这意味着\(B\)的线性空间包含在\(A\)的线性空间内。由于\(|A|<|B|\)\(A,B\)各自线性无关,矛盾。因此存在交换性。
??因此这是一个拟阵。我们就可以按照装备的花费,维护线性无关组,从小到大进行贪心。
??怎么维护线性无关组呢?
??如果每次检查都用高斯消元,时间会被卡到\(O(n^4)\),当然是不可以的。
??我们一个常用于维护线性无关组的结构——线性基。
??考虑魔改线性基。我们将向量看成 “ \(x\) 进制 ” 的数。插入向量\(\boldsymbol z\)的时候,在\(x_i\)位上,如果没有元素就插入\(z\);否则我们用线性基上的元素,将\(\boldsymbol z\)上的\(x_i\)的系数消成 0 。对于一个向量,如果可以插入到线性基中,就说明它加入后组内仍然是线性无关的,需要计入答案。
??时间\(O(n^3)\)

代码

#include <cstdio>
#include <algorithm>

#define spawn vector ret = vector()
#define rush for( int i = 1 ; i <= M ; i ++ )
#define op( c ) vector operator c ( vector b ) const { spawn; rush ret[i] = vec[i] c b[i]; return ret; }
#define reop( c ) void operator c##= ( vector b ) { *this = *this c b; } 

const double eps = 1e-4;
const int MAXN = 505, MAXM = 505;

template<typename _T>
void read( _T &x )
{
	x = 0;char s = getchar();int f = 1;
	while( s > ‘9‘ || s < ‘0‘ ){if( s == ‘-‘ ) f = -1; s = getchar();}
	while( s >= ‘0‘ && s <= ‘9‘ ){x = ( x << 3 ) + ( x << 1 ) + ( s - ‘0‘ ), s = getchar();}
	x *= f;
}

template<typename _T>
void write( _T x )
{
	if( x < 0 ){ putchar( ‘-‘ ); x = ( ~ x ) + 1; }
	if( 9 < x ){ write( x / 10 ); }
	putchar( x % 10 + ‘0‘ );
}

template<typename _T>
_T ABS( _T x )
{
	return x < 0 ? -x : x;
}

int cost[MAXN], seq[MAXN];
int N, M;
bool taken[MAXM];

struct vector
{
	double vec[MAXN];
	vector() { for( int i = 0 ; i < MAXM ; i ++ ) vec[i] = 0; }
	double& operator [] ( const int indx ) { return vec[indx]; }
	op( + ) op( - ) reop( + ) reop( - )
	vector operator * ( const double &b ) const { spawn; rush ret[i] = vec[i] * b; return ret; }
};

vector base[MAXM], z[MAXN];

bool cmp( const int &x, const int &y ) { return cost[x] < cost[y]; }
bool equal( const double a, const double b = 0 ) { return ABS( a - b ) <= eps; }

bool insert( const int indx )
{
	double coe;
	for( int i = 1 ; i <= M ; i ++ )
		if( ! equal( z[indx][i] ) )
		{
			if( ! taken[i] ) { taken[i] = true, base[i] = z[indx]; return true; }
			coe = z[indx][i] / base[i][i];
			z[indx] -= base[i] * coe;
		}
	return false;
}

int main()
{
	int v, ans = 0, tot = 0;
	read( N ), read( M );
	for( int i = 1 ; i <= N ; i ++ )
		for( int j = 1 ; j <= M ; j ++ )
			read( v ), z[i][j] = v;
	for( int i = 1 ; i <= N ; i ++ ) read( cost[i] ), seq[i] = i;
	std :: sort( seq + 1, seq + 1 + N, cmp );
	for( int i = 1 ; i <= N ; i ++ )
		if( insert( seq[i] ) )
			tot ++, ans += cost[seq[i]];
	write( tot ), putchar( ‘ ‘ ), write( ans ), putchar( ‘\n‘ );
	return 0;
}

[JLOI2015]装备购买

标签:exist   strong   struct   常用   equal   http   cst   max   spawn   

原文地址:https://www.cnblogs.com/crashed/p/12742251.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!