分析:題目很裸,最大購買個數就是線性無關向量的個數。要使得花錢最少,可以套用貪心的思想。
反思:犯了一個錯誤,學了高斯消元后想在高斯消元的過程中得到解,但在高斯消元的過程中貪心並不是正解,似乎會影響到後面的決策使得總花費不是最優。這題要用線性基,線性基求基的過程是枚舉每一個向量,看這個向量能加到哪一行,如果當前行向量已存在那麼對這個向量進行初等變換使得向量該位置爲0,這樣會保證線性基的每一個向量的最左端不爲0的位置不同,最終加進去的各個向量線性無關。(學過線性代數會發現這就是模擬求矩陣的秩的過程,每次加入一個和已經得到的向量組線性無關的向量來得到一個更大的線性無關向量組,最終加不可加時就得到了極大線性無關向量組)
花費最小:考慮貪心,將向量按價格從小到大排序。總是先將價格最低的向量加入到線性無關向量組中,設某一行加入的向量並不是當前花費最小的向量,那麼用這個花費最小的向量代替所選擇的這個向量仍然可以構成一個線性基,它們的線性空間相同,而總花費更小。
關於精度問題:這題卡了精度,eps開到幾都沒用,查了一下黑科技就是使用求模意義下的指,只要模數夠大就不會影響答案。這題可以用作爲模數。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e2 + 10;
const int mod = 1e9 + 7;
typedef long long ll;
int n,m;
ll a[maxn][maxn];
int p[maxn],c[maxn],b[maxn];
bool cmp(int a,int b) {
return c[a] < c[b];
}
ll fpow(ll a,ll b) {
ll r = 1;
while(b) {
if(b & 1) r = r * a % mod;
a = a * a % mod;
b >>= 1;
}
return r;
}
int main() {
memset(b,0,sizeof b);
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
scanf("%lld",&a[i][j]);
for(int i = 1; i <= n; i++) {
scanf("%d",&c[i]);
p[i] = i;
}
sort(p + 1,p + n + 1,cmp);
int ans = 0,res = 0;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
if(a[p[i]][j]) {
if(!b[j]) {
b[j] = p[i];
ans += c[p[i]];
res++;
break;
}
else {
ll rate = a[p[i]][j] * fpow(a[b[j]][j],mod - 2) % mod;
for(int k = 1; k <= m; k++)
a[p[i]][k] = (a[p[i]][k] - a[b[j]][k] * rate % mod + mod) % mod;
}
}
}
}
printf("%d %d\n",res,ans);
return 0;
}