• [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;
    }
    
  • 相关阅读:
    [Luogu P4779] 单源最短路径(标准版)
    [Luogu P1659] 拉拉队排练
    [Luogu P3435] OKR-Periods of Words
    [Poj #2127] Greatest Common Increasing Subsequence
    [Poj #2019] Cornfields
    [Poj #1949] Chores
    关于我
    划水记录
    [AGC006C] Rabbit Exercise
    [AGC007C] Pushing Balls
  • 原文地址:https://www.cnblogs.com/crashed/p/12742251.html
Copyright © 2020-2023  润新知