這道題也是高斯消元解異或方程組,可是書上寫的程序是有問題的。html
用這個數據能夠hack掉:ide
1spa
3code
0 0 0htm
1 1 1blog
1 2get
2 1string
2 3it
0 0io
列出矩陣:
1 1 0 1
1 1 1 1
0 0 1 1
而後就會給出無解。其實是有2解的。
下面來看正解:
異或方程組不能往上回消,也不能像書上那樣每次把上下都消了。
直接消成上三角矩陣。
答案就是 (1 << 自由元個數)
關於無解的斷定:自由元常數項和前面不統一時即無解。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 const int N = 35; 5 6 int a[N], n; 7 8 inline int Gauss() { 9 int ans = 0; 10 for(int i = 1; i <= n; i++) { 11 for(int j = i; j <= n; j++) { 12 if(a[j] & (1 << i)) { 13 std::swap(a[i], a[j]); 14 break; 15 } 16 } 17 if(!((a[i] >> i) & 1)) { 18 if((a[i] > 1) ^ (a[i] & 1)) { 19 return -1; 20 } 21 else { 22 ans++; 23 continue; 24 } 25 } 26 for(int j = i + 1; j <= n; j++) { 27 if(a[j] & (1 << i)) { 28 a[j] ^= a[i]; 29 } 30 } 31 } 32 return ans; 33 } 34 35 inline void solve() { 36 scanf("%d", &n); 37 int c, b; 38 for(int i = 1; i <= n; i++) { 39 scanf("%d", &a[i]); 40 } 41 for(int i = 1; i <= n; i++) { 42 scanf("%d", &b); 43 a[i] ^= b; 44 } 45 while(scanf("%d%d", &c, &b)) { 46 if(!c) { 47 break; 48 } 49 a[b] |= (1 << c); 50 } 51 for(int i = 1; i <= n; i++) { 52 a[i] |= (1 << i); 53 } 54 55 int t = Gauss(); 56 if(t == -1) { 57 printf("Oh,it's impossible~!!\n"); 58 return; 59 } 60 printf("%d\n", 1 << t); 61 return; 62 } 63 64 int main() { 65 int T; 66 scanf("%d", &T); 67 while(T--) { 68 solve(); 69 if(T) { 70 memset(a, 0, sizeof(a)); 71 } 72 } 73 return 0; 74 }
可是無論怎麼說,有一點讓我很在乎:
高斯消元解異或方程組的時候,兩行異或這個操做的實際意義是什麼?
如今我可能有答案了。
沒有意義,不要聯繫實際,而是當成方程的形式,在每一項後面配一個xj就好了。
而後聯繫這一題:
本題求方案數,因此能夠直接用2^ans
可是那一題求最小值,而每一個主元雖然說固定,可是分選/不選兩種。
而後自由元的選/不選雖然不會改變主元的個數,可是能改變主元的狀態。
因此須要DFS。
可是還有個問題:爲何不能往上回消呢?
反正記住就行了。