[JLOI2015]裝備購買,洛谷P3265,實數線性基
阿新 • • 發佈:2018-11-09
正題
回想線性基的過程,是不是碰到第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); }