Luogu P3265 [JLOI2015]装备购买

一道真正意义下的线性基裸题

平时我们说的关于线性基在OI中主要针对二进制下的,而这里的线性基回归了本源,是关于向量的线性基

我们考虑二进制下线性基的算法,它主要就是将数分解成许多个二进制位

然后在每一位的放入对应的数来消去后面的数,主要用的是异或

而关于向量的呢,我们考虑在向量的每一位放入对应的向量,然后用当前的这一位去消去之后的这一位

那么具体怎么操作呢,其实就是个高斯消元的过程,因此我们就类比得出了一般线性基的构造方式

然后对于这题,我们可以想到贪心地把装备按价值从小到大加入,因为若存在一组向量线性相关,那么肯定是删去较大的那个才会更优

因此这题就做完了,注意精度会有点卡,建议开long double

CODE

#include<cstdio>
#include<cmath>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
const int N=505;
const long double EPS=1e-6;
struct data
{
    long double mat[N]; int val;
    inline long double& operator [] (CI x) { return mat[x]; }
    friend inline bool operator < (const data& A,const data& B)
    {
        return A.val<B.val;
    }
}a[N]; int n,m,p[N],ans1,ans2;
int main()
{
    RI i,j,k; for (scanf("%d%d",&n,&m),i=1;i<=n;++i)
    for (j=1;j<=m;++j) scanf("%Lf",&a[i][j]);
    for (i=1;i<=n;++i) scanf("%d",&a[i].val);
    for (sort(a+1,a+n+1),i=1;i<=n;++i) for (j=1;j<=m;++j)
    {
        if (fabs(a[i][j])<EPS) continue;
        if (!p[j]) { p[j]=i; ++ans1; ans2+=a[i].val; break; }
        double dv=1.0*a[i][j]/a[p[j]][j];
        for (k=j;k<=m;++k) a[i][k]-=dv*a[p[j]][k];
    }
    return printf("%d %d",ans1,ans2),0;
}
posted @ 2019-06-30 21:36 hl666 阅读(...) 评论(...) 编辑 收藏