【高斯消元解xor方程】BZOJ1923-[Sdoi2010]外星千足虫
【题目大意】
有n个数或为奇数或为偶数,现在进行m次操作,每次取出部分求和,告诉你这几次操作选取的数和它们和的奇偶性。如果通过这m次操作能得到所有数的奇偶性,则输出进行到第n次时即可求出答案;否则输出无法确定。
【思路】
高斯消元解xor方程组,求最少需要的方程个数或判断无法确定。
无法确定即存在自由元,在每次操作中找1的时候判断一下就好了;最小方程个数,就是记录下每次找到的最小的1的位置,最后输出最大值即可。
【错误】
忘记把ans改为-1了(见程序注释)
【备注】
P.S.我看别人在高斯消元的过程中都是当前行和所有行xor一遍,而不是从下一行开始;然后结果就不需要回代了只需直接输出第n+1列即可??不适合呢明白????
在莫涛和proverbs那里找到答案了:
考虑系数矩阵,每行是一个方程,每列是一个未知数在各个方程中的系数(将第i行的方程的所有系数状压到一个数 a[i]里,可以用bitset)。
我们分析一下消元之后各个方程系数的状况:
由于我们每次选择最大的一个 a[i],并且找到它最高位上的1,把其它所有方程(包含当前行以上的方程)这一位的系数全部消去,也就是说对于每个方程,它的系数 a[i]最高位上的1所在的那一列,仅有这一个1,其余的都是0。再进一步,如果方程个数n足够多的话,那么消元之后系数矩阵的每一行仅有一个1,并且这个1所在的那一列也仅有这一个1。
1 /*回代的做法*/ 2 /************************************************************** 3 Problem: 1923 4 Language: C++ 5 Result: Accepted 6 Time:244 ms 7 Memory:1556 kb 8 ****************************************************************/ 9 10 #include<iostream> 11 #include<cstdio> 12 #include<cstring> 13 #include<algorithm> 14 #include<bitset> 15 using namespace std; 16 const int MAXN=1000+50; 17 const int MAXM=2000+50; 18 bitset<MAXN> map[MAXM]; 19 int n,m; 20 int times=-1; 21 22 void Gauss() 23 { 24 for (int i=1;i<=n;i++) 25 { 26 int t=i; 27 for (;t<=m && !map[t][i];t++); 28 if (t>m) 29 { 30 times=-1;//这里times要清成-1 31 return; 32 } 33 if (t!=i) swap(map[i],map[t]); 34 times=max(times,t); 35 for (int j=i+1;j<=m;j++) 36 if (map[j][i]) 37 map[j]^=map[i]; 38 } 39 40 } 41 42 void init() 43 { 44 scanf("%d%d",&n,&m); 45 for (int i=0;i<m;i++) 46 { 47 char str[MAXN]; 48 int mapans; 49 scanf("%s%d",str,&mapans); 50 map[i+1][n+1]=mapans; 51 for (int j=0;j<n;j++) map[i+1][j+1]=str[j]-'0'; 52 } 53 } 54 55 void print_ans() 56 { 57 if (times==-1) cout<<"Cannot Determine"<<endl; 58 else 59 { 60 printf("%d\n",times); 61 for (int i=n;i>=1;i--) 62 for (int k=i+1;k<=n;k++) 63 if (map[i][k]) 64 { 65 int tmp=map[i][n+1]^map[k][n+1]; 66 map[i][n+1]=tmp; 67 } 68 for (int i=1;i<=n;i++) 69 puts((map[i][n+1])?"?y7M#":"Earth"); 70 } 71 } 72 73 int main() 74 { 75 init(); 76 Gauss(); 77 print_ans(); 78 }
额变慢了……仿佛被欺骗了感情……谁来告诉我一下??!!
/*不回代的做法*/ /************************************************************** Problem: 1923 Language: C++ Result: Accepted Time:284 ms Memory:1556 kb ****************************************************************/ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<bitset> using namespace std; const int MAXN=1000+50; const int MAXM=2000+50; bitset<MAXN> map[MAXM]; int n,m; int times=-1; void Gauss() { for (int i=1;i<=n;i++) { int t=i; for (;t<=m && !map[t][i];t++); if (t>m) { times=-1;//这里times要清成-1 return; } if (t!=i) swap(map[i],map[t]); times=max(times,t); for (int j=1;j<=m;j++) if (i!=j && map[j][i]) map[j]^=map[i]; } } void init() { scanf("%d%d",&n,&m); for (int i=0;i<m;i++) { char str[MAXN]; int mapans; scanf("%s%d",str,&mapans); map[i+1][n+1]=mapans; for (int j=0;j<n;j++) map[i+1][j+1]=str[j]-'0'; } } void print_ans() { if (times==-1) cout<<"Cannot Determine"<<endl; else { printf("%d\n",times); for (int i=1;i<=n;i++) puts((map[i][n+1])?"?y7M#":"Earth"); } } int main() { init(); Gauss(); print_ans(); }