[JLOI2015]装备购买

线性空间向量基底板子。
不同于异或空间的线性基。
我们考虑求出这些向量的基底,我们只要按照价值小的先插即可,最后选择 \(k\) 个向量底即可。
我们发现如果一个向量可能成为底,则他的价值一定最小。

#pragma optimize(2)
#include<bits/stdc++.h>
using namespace std;
template<typename T>
inline void read(T &x){
	x=0;char c=getchar();bool f=false;
	for(;!isdigit(c);c=getchar())f!=c=='-';
	for(;isdigit(c);c=getchar())x=x*10+c-'0';
	if(f)x=-x;
}
template<typename T ,typename ...Arg>
inline void read(T &x,Arg &...args){
	read(x);read(args...);
}
template<typename T>
inline void write(T x){
	if(x<0)putchar('-'),x=-x;
	if(x>=10)write(x/10);
	putchar(x%10+'0');
}
const int max_wei=700;
const long double eps=1e-5; 
int n,m,num=0,cost=0;;
template<class T>
struct Vector{
	T a[max_wei];
	void init(){for(int i=0;i<m;i++)a[i]=0;}
	Vector operator+(const Vector b)const{
		Vector<T> c;c.init();for(int i=0;i<m;i++)
		c.a[i]=a[i]+b.a[i];return c;
	}
	Vector operator-(const Vector b)const{
		Vector<T> c;c.init();for(int i=0;i<m;i++)
		c.a[i]=a[i]-b.a[i];return c;
	}
	Vector operator*(T x)const{
		Vector<T> c;c.init();for(int i=0;i<m;i++)
		c.a[i]=a[i]*x;return c;
	}
};
struct Leaner_Basis{
	Vector<long double>b[max_wei];
	bool insert(Vector<long double> c){//将向量c插入线性基 并返回能否插入 
		for(int i=m-1;i>=0;i--) {
			if(abs(c.a[i])<eps)continue;
			if(abs(b[i].a[i])<eps){b[i]=c;return true;}
			long double t=c.a[i]/b[i].a[i];
			c=c-b[i]*t;
		} 
		return false;
	}
}B;
struct node{
	int cost;
	Vector<long double>c;
	bool operator<(const node b)const{
	return cost<b.cost;}
}a[500+10];
signed main(){
	//freopen("buy.in","r",stdin);
	//freopen("buy.out","w",stdout);
	read(n,m);
	for(int i=1;i<=n;i++)
		for(int j=0;j<m;j++)
			read(a[i].c.a[j]);
	for(int i=1;i<=n;i++)
		read(a[i].cost);
	sort(a+1,a+1+n);
	for(int i=1;i<=n;i++)
		if(B.insert(a[i].c))
			num++,cost+=a[i].cost;
	printf("%d %d",num,cost);
}
posted @ 2021-08-29 10:24  fhq_treap  阅读(30)  评论(0编辑  收藏  举报