zoukankan      html  css  js  c++  java
  • [JLOI2015]装备购买

    题目

      点这里看题目。

    分析

      可以发现,一组装备可以同时购买的条件是这组装备线性无关
      首先不难发现一个拟阵(M=<S,I>),其中:
      (S)为装备的集合;如果(Asubseteq S),那么(Ain I)当且仅当(A)内的元素线性无关。
      显然(M)是一个子集系统,考虑一下它的交换性:
      对于(A,Bin I),如果(|A|<|B|),我们需要证明(exists xin B-A, Acup {x}in I),即新的集合仍然线性无关。
      考虑反证法,即假设不存在这样的(x)。这意味着(forall xin B-A)(x)都可以在(A)中表示出来。那么(B)中的元素都可以在(A)中表示出来。这意味着(B)的线性空间包含在(A)的线性空间内。由于(|A|<|B|)(A,B)各自线性无关,矛盾。因此存在交换性。
      因此这是一个拟阵。我们就可以按照装备的花费,维护线性无关组,从小到大进行贪心。
      怎么维护线性无关组呢?
      如果每次检查都用高斯消元,时间会被卡到(O(n^4)),当然是不可以的。
      我们一个常用于维护线性无关组的结构——线性基。
      考虑魔改线性基。我们将向量看成 “ (x) 进制 ” 的数。插入向量(oldsymbol z)的时候,在(x_i)位上,如果没有元素就插入(z);否则我们用线性基上的元素,将(oldsymbol 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( '
    ' );
    	return 0;
    }
    
  • 相关阅读:
    Python元组、列表、字典
    测试通过Word直接发布博文
    Python环境搭建(windows)
    hdu 4003 Find Metal Mineral 树形DP
    poj 1986 Distance Queries LCA
    poj 1470 Closest Common Ancestors LCA
    poj 1330 Nearest Common Ancestors LCA
    hdu 3046 Pleasant sheep and big big wolf 最小割
    poj 3281 Dining 最大流
    zoj 2760 How Many Shortest Path 最大流
  • 原文地址:https://www.cnblogs.com/crashed/p/12742251.html
Copyright © 2011-2022 走看看