1. 程式人生 > 實用技巧 >線性基

線性基

利用高斯消元來判斷向量能否被前面的向量張成

我們每次維護一個對角矩陣。執行到第ii步的時候,我們從高到低考慮數a_iai​​為11的二進位制位jj,如果jj這一行的對角線已經為11了,那麼我們不能加入,同時為了保持上三角性質,需要將第jj行的行向量異或到\mathbf{a}_iai​​;如果jj這一行的對角線為00,那麼我們就可以將\mathbf{a}_iai​​新增到這一行,同時為了維護一個對角矩陣,要先用下面的行消自己,再用自己消上面的行。

例題 HDU 3949 XOR

注意不存在的條件 以及能否湊出0

#pragma warning(disable:4996)

#include
<iostream> #include<algorithm> //#include<unordered_map> #include<fstream> #include<iomanip> #include<string> #include<cmath> #include<cstring> #include<vector> #include<map> #include<set> #include<list> #include<queue> #include
<stack> #include<sstream> #include<cstdio> #include<ctime> #include<cstdlib> #define INF 0x3f3f3f3f #define inf 0x7FFFFFFF #define MOD 1000000007 #define moD 1000000003 #define pii pair<string,int> #define eps 1e-7 #define equals(a,b) (fabs(a-b)<eps) #define bug puts("bug") #define
re register #define fi first #define se second const int maxn = 1e4 + 5; const double Inf = 10000.0; const double PI = acos(-1.0); typedef long long ll; using namespace std; const int max_base = 63; int n; ll a[maxn]; ll b[max_base+5]; vector<ll> v; bool flag; void cal() { int cnt = 0; memset(b, 0, sizeof b); for (int i = 0; i < n; ++i) for (int j = max_base; j >= 0; --j) if (a[i] >> j & 1) { if (b[j]) a[i] ^= b[j]; else { b[j] = a[i] , cnt++; for (int k = j - 1; k >= 0; --k) if (b[k] && ((b[j] >> k) & 1)) b[j] ^= b[k]; for (int k = j + 1; k <= max_base; ++k) if ((b[k] >> j) & 1) b[k] ^= b[j]; break; } } v.clear(); for (int i = 0; i <= max_base; i++) { if (b[i]) v.push_back(b[i]); } flag = (n != cnt); } ll query(ll k) { if (flag) k--; //cout << v.size() << " xxx " << endl; if (k >= (1ll<<v.size())) return -1; ll ans = 0; for (int i = 0; i < v.size(); i++) if ((k >> i) & 1) ans ^= v[i]; return ans; } int main() { int T; int kase = 1; scanf("%d", &T); while (T--) { scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%lld", a + i); cal(); int m; scanf("%d", &m); printf("Case #%d:\n", kase++); while (m--) { ll k; scanf("%lld", &k); ll ans = query(k); printf("%lld\n", ans); } } }