【高斯消元解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();
}
时间: 2024-10-08 01:02:16

【高斯消元解xor方程】BZOJ1923-[Sdoi2010]外星千足虫的相关文章

【高斯消元解XOR方程】POJ1222-EXTENDED

[题目大意] 有5*6盏灯,每次开/关一个灯,上下左右的灯状态也会反转.问怎么使状态统一? [思路] 典型高斯消元解XOR方程,注意每盏灯要么0次要么1次. 1 #include <iostream> 2 #include <stdio.h> 3 #include <algorithm> 4 #include <set> 5 using namespace std; 6 int a[40][40]; 7 void gauss() 8 { 9 int i,j,

【高斯消元】【异或方程组】【bitset】bzoj1923 [Sdoi2010]外星千足虫

Xor方程组解的个数判定: ——莫涛<高斯消元解Xor方程组> 使用方程个数判定:消去第i个未知数时,都会记录距第i个方程最近的第i位系数不为0の方程是谁,这个的max就是使用方程个数. 使用bitset加速. #include<cstdio> #include<cmath> #include<algorithm> #include<bitset> using namespace std; #define N 1001 #define M 200

【题解】 bzoj1923: [Sdoi2010]外星千足虫 (线性基/高斯消元)

bzoj1923,戳我戳我 Solution: 这个高斯消元/线性基很好看出来,主要是判断在第K 次统计结束后就可以确定唯一解的地方和\(bitset\)的骚操作 (我用的线性基)判断位置,我们可以每次加入一个线性基时判断是不是全被异或掉了,如果没有,说明这个方程不是冗余的,那么我们可记录非冗余方程个数 如果非冗余方程个数小于\(n\),那就是个不定方程组,有无数种解,否则,在个数第一次达到\(n\)时,就可输出当时输入方程的号码 还有一个点就是压空间与时间,这题主要是时间,用到大杀器\(bit

bzoj1923[Sdoi2010]外星千足虫(高斯消元)

Description Input 第一行是两个正整数 N, M. 接下来 M行,按顺序给出 Charles 这M次使用"点足机"的统计结果.每行 包含一个"01"串和一个数字,用一个空格隔开."01"串按位依次表示每只虫 子是否被放入机器:如果第 i 个字符是"0"则代表编号为 i 的虫子未被放入,"1" 则代表已被放入.后面跟的数字是统计的昆虫足数 mod 2 的结果. 由于 NASA的实验机器精确无误

POJ 1222 EXTENDED LIGHTS OUT(高斯消元解XOR方程组)

http://poj.org/problem?id=1222 题意:现在有5*6的开关,1表示亮,0表示灭,按下一个开关后,它上下左右的灯泡会改变亮灭状态,要怎么按使得灯泡全部处于灭状态,输出方案,1表示按,0表示不按. 思路:每个开关最多只按一次,因为按了2次之后,就会抵消了. 可以从结果出发,也就是全灭状态怎么按能变成初始状态. 用3*3来举个例子,$X\left ( i,j \right )$表示这些开关是按还是不按,那么对于第一个开关,对它有影响的就只有2.4这两个开关,所以它的异或方程

BZOJ1923 [Sdoi2010]外星千足虫 【高斯消元】

题目 输入格式 第一行是两个正整数 N, M. 接下来 M行,按顺序给出 Charles 这M次使用"点足机"的统计结果.每行 包含一个"01"串和一个数字,用一个空格隔开."01"串按位依次表示每只虫 子是否被放入机器:如果第 i 个字符是"0"则代表编号为 i 的虫子未被放入,"1" 则代表已被放入.后面跟的数字是统计的昆虫足数 mod 2 的结果. 由于 NASA的实验机器精确无误,保证前后数据不会自

BZOJ1923: [Sdoi2010]外星千足虫

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1923 高斯消元. (bitset好优越啊.. #include<cstring> #include<iostream> #include<algorithm> #include<cstdio> #include<queue> #include<bitset> #define rep(i,l,r) for (int i=l;i<

关于高斯消元解决xor问题的总结

我觉得xor这东西特别神奇,最神奇的就是这个性质了 A xor B xor B=A 这样就根本不用在意重复之类的问题了 关于xor的问题大家可以去膜拜莫队的<高斯消元解XOR方程组>,里面写的很详细 我来扯两道bzoj上的例题好了 bzoj2115,求1-N最长xor路径,根据那个神奇的性质,我们先随便找一条1-n的路径作为标准路径 任意一条1-N的路径都等价于标准路径和某些环的xor 怎么找环?很简单,bfs下去,设d[x]表示1到x的一条路径xor值,如果到一条边x-->y时y已经访

【BZOJ-1923】外星千足虫 高斯消元 + xor方程组

1923: [Sdoi2010]外星千足虫 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 766  Solved: 485[Submit][Status][Discuss] Description Input 第一行是两个正整数 N, M. 接下来 M行,按顺序给出 Charles 这M次使用“点足机”的统计结果.每行包含一个“01”串和一个数字,用一个空格隔开.“01”串按位依次表示每只虫子是否被放入机器:如果第 i 个字符是“0”则代表编号为