BZOJ 4004 [JLOI 2015] 装备购买 解题报告
哎这个题 WA 了无数遍。。。果然人太弱。。。
首先我们把这些装备按照花费从小到大排序,然后依次考虑是否能买这个装备。
至于这样为什么是对的,好像有一个叫拟阵的东西可以证明,然而我不会。TATQAQ
至于怎么考虑是否能买这个装备呢,我们可以动态更新线性基,具体操作:
- 对当前向量进行高斯消元,注意要从从高位往低位消。
- 如果消元完毕后当前向量变成了 $0$ 向量,那么我们就可以用之前的装备凑出当前装备,否则就不能凑出来。
每次更新线性基需要 $O(m^2)$ 的时间,要更新 $O(n)$ 次。
时间复杂度 $O(nm^2)$,稍微优化一下应该可以过吧。。。
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <iostream> 5 #include <algorithm> 6 using namespace std; 7 typedef long long LL; 8 #define N 500 + 5 9 #define Mod 998244353 10 11 int n, m, tot, ans; 12 int Ord[N], W[N]; 13 14 struct Node 15 { 16 int num[N]; 17 Node () {memset(num, 0, sizeof(num));} 18 inline void init() 19 { 20 for (int i = 1; i <= m; i ++) 21 scanf("%d", num + i); 22 } 23 inline bool operator < (const Node a) const 24 { 25 for (int i = 1; i <= m; i ++) 26 { 27 if (num[i] != 0 && !a.num[i]) return 0; 28 else if (!num[i] && a.num[i] != 0) return 1; 29 } 30 return 0; 31 } 32 }A[N], P[N]; 33 34 inline int power(int u, int v) 35 { 36 int res = 1; 37 for (; v; v >>= 1) 38 { 39 if (v & 1) res = (LL) res * u % Mod; 40 u = (LL) u * u % Mod; 41 } 42 return res; 43 } 44 45 inline bool cmp(int u, int v) 46 { 47 return W[u] < W[v]; 48 } 49 50 inline bool All_zero(int id) 51 { 52 for (int i = 1; i <= m; i ++) 53 if (A[id].num[i] != 0) return 0; 54 return 1; 55 } 56 57 inline int Inc(int a, int b) 58 { 59 return a + b - (a + b >= Mod ? Mod : 0); 60 } 61 62 inline bool Modify(int id) 63 { 64 if (tot == m) return 0; 65 if (!tot) 66 { 67 tot ++; 68 for (int i = 1; i <= m; i ++) 69 P[tot].num[i] = A[id].num[i]; 70 return 1; 71 } 72 for (int d = 1; d <= tot; d ++) 73 { 74 int i = 1; 75 for (; i <= m; i ++) 76 if (P[d].num[i] != 0) break ; 77 if (!A[id].num[i]) continue ; 78 int mul = (LL) A[id].num[i] * power(P[d].num[i], Mod - 2) % Mod; 79 for (i = 1; i <= m; i ++) 80 A[id].num[i] = Inc(A[id].num[i], Mod - ((LL) P[d].num[i] * mul % Mod)); 81 } 82 bool ok = 0; 83 for (int i = 1; !ok && i <= m; i ++) 84 if (A[id].num[i] != 0) ok = 1; 85 if (!ok) return 0; 86 tot ++; 87 for (int i = 1; i <= m; i ++) 88 P[tot].num[i] = A[id].num[i]; 89 for (int d = tot; d > 1; d --) 90 { 91 if (P[d - 1] < P[d]) 92 { 93 for (int i = 1; i <= m; i ++) 94 swap(P[d - 1].num[i], P[d].num[i]); 95 } 96 else break ; 97 } 98 return 1; 99 } 100 101 int main() 102 { 103 #ifndef ONLINE_JUDGE 104 freopen("4004.in", "r", stdin); 105 freopen("4004.out", "w", stdout); 106 #endif 107 108 scanf("%d%d", &n, &m); 109 for (int i = 1; i <= n; i ++) 110 A[i].init(); 111 for (int i = 1; i <= n; Ord[i] = i ++) 112 scanf("%d", W + i); 113 sort(Ord + 1, Ord + n + 1, cmp); 114 for (int i = 1; i <= n; i ++) 115 { 116 int _i = Ord[i]; 117 if (All_zero(_i)) continue ; 118 if (Modify(_i)) ans += W[_i]; 119 } 120 if (!tot) ans = W[Ord[1]], tot = 1; 121 printf("%d %d\n", tot, ans); 122 123 #ifndef ONLINE_JUDGE 124 fclose(stdin); 125 fclose(stdout); 126 #endif 127 return 0; 128 }