正题
回想线性基的过程,是不是碰到第i位有数,就必须把第i位清空?
其实这个就是一个高斯消元的过程,只不过他少了未知数。
这题当然也可以用高斯消元做,看一下当前这个能不能被前面的构造出来,这样的复杂度会显得很高。
思考运用线性基的性质。
第i位为1。第i个数下面的数的第i位肯定为0.
那么现在线性基存的就是一个向量,每次遇到第x位不为0,而且线性基中这里有向量,那就把向量减去线性基中的向量乘上一个数。(初等变换)
然后如果没有向量就存进去。
到最后如果可以被线性基中的向量组合出来,那么这个装备(向量)就没必要买。
从小到大放,不能放的就丢掉,得到的一定是最小的数,而且可以证明取的装备一定是最大的(别问我,要问我的感性
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct node{
double a[510];
int d;
bool operator<(const node x)const{
return d<x.d;
}
}s[510];
int n,m;
double p[510][510];
bool tf[510];
double eps=1e-5;
bool insert(node x){
bool we=false;
for(int i=m;i>=1;i--)
if(fabs(x.a[i])>eps){
if(tf[i]) for(int j=1;j<=i;j++) x.a[j]-=p[i][j]*x.a[i]/p[i][i];
else{
for(int j=i;j>=1;j--) p[i][j]=x.a[j];
we=true;tf[i]=true;
break;
}
}
return we;
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=m;j>=1;j--)
scanf("%lf",&s[i].a[j]);
for(int i=1;i<=n;i++) scanf("%d",&s[i].d);
sort(s+1,s+1+n);
int ans=0,t=0;
for(int i=1;i<=n;i++) if(insert(s[i])) ans+=s[i].d,t++;
printf("%d %d\n",t,ans);
}