BZOJ 4004 [JLOI 2015] 装备购买 解题报告

哎这个题 WA 了无数遍。。。果然人太弱。。。

首先我们把这些装备按照花费从小到大排序,然后依次考虑是否能买这个装备。

至于这样为什么是对的,好像有一个叫拟阵的东西可以证明,然而我不会。TATQAQ

至于怎么考虑是否能买这个装备呢,我们可以动态更新线性基,具体操作:

  1. 对当前向量进行高斯消元,注意要从从高位往低位消。
  2. 如果消元完毕后当前向量变成了 $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 }
4004_Gromah

 

posted @ 2015-04-27 20:32  Gromah  阅读(421)  评论(0编辑  收藏  举报