一道真正意义下的线性基裸题
平时我们说的关于线性基在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;
}