codeforces-div1-285-D

来源:互联网 发布:邵氏弃儿 后续 知乎 编辑:程序博客网 时间:2024/05/17 08:54

题目链接:Misha and XOR


解法:

首先对于每个数, 先讲其转换为二进制, 转换的方法就是模拟大数除法, 转化的时候最好压缩几位, 这样速度快些.

然后问题其实就变成了, 对于某个二进制数, 能否用出现在它之前的那些二进制数表示.

有点经验的话, 就很容易发现需要用高斯消元法来解决.

但是高斯消元法的复杂度是m^3(m为矩阵大小), 这里一共有n个数, 复杂度就是n*m^3, 对于这里的数据, 明显超时了.

由于这些数是按照顺序加入的, 每加入一个数就询问能否由前面的数组成, 这样就可以根据这个顺序性, 每次加入数过后, 维护一些东西, 以求降低复杂度.


假如现在加入到了第k个数, 那么我们就维护0~k个数构成的矩阵, 转化成阶梯形式过后, 每行现在的值, 每行第一个非0元素的位置, 以及每行被哪些行异或过, 有些拗口, 下面有个例子.

比如第一个元素为 1100(十进制的3), 把这个元素加入过后, 我们维护了第一行的这些东西: 这一行的值为1100, 第一个非0元素在第0位, 构成这一行的数有第1个数;

现在第二个元素为 1000(十进制的2), 先把这个元素加到矩阵的第二行, 于是现在的矩阵为

1100

1000 

现在把他变为阶梯矩阵, 

1100

0100

现在再来维护第二行的东西: 这一行值为0100, 第一个非0元素在第1位, 构成这一行的数有第1, 2个数(因为这一行实际上是有第一二个数异或得来)


现在考虑一下询问, 

假如第三个数是1000(1), 我们就可以根据刚才维护的阶梯矩阵来求解他的值, 

首先我们看他第0位是1, 因此我们需要把它和第一行进行异或来抵消这个1, 现在它的值就变成了0100, 

然后我们看它第1位是1, 因此我们需要把它和第二行进行异或来抵消这个1, 现在它是0000, 

发现它现在是0000, 就说明它能够由之前的数字构成了.

如果异或完后的值不等于0, 那么说明它不能由之前数字构成.


下面是代码

#include <stack>#include <stdio.h>#include <iostream>#include <string.h>#include <vector>#include <math.h>#include <queue>#include <map>#include <set>#include <algorithm>#include <bitset>using namespace std;#define FOR(i, j, k) for(int i=(j);i<=(k);i++)#define REP(i, n) for(int i=0;i<(n);i++)#define mst(x, y) memset(x, y, sizeof(x));#define pii pair<int, int>#define fr first#define sc second#define left myleft#define right myright#define ll long long#define ull unsigned long long#define seed 1331#define eps 1e-5#define pdd pair<double, double>#define inf 1e9const int lim = 2050;int n, first[lim];bitset <lim> row[lim], who[lim], x, ans;char s[666];void read(){scanf("%s", s);}void convert(){    x.reset();    int len = strlen(s), pos = 0;    REP(i, len) s[i] -= '0';    while(len){        ll base = (ll)1<<50, remain = 0;        int p = 0;        REP(i, len){            ll sum = remain*10 + s[i];            if(sum >= base || p)  s[p ++] = sum / base;            remain = sum % base;        }        REP(i, 50) x[pos ++] = remain & 1, remain /= 2;        len = p;    }}int main(){//    freopen("4", "r", stdin);    cin>>n;    REP(k, n){        read();        convert();        ans.reset();        ans.set(k);        REP(i, k) if(x.test(first[i]))            x ^= row[i], ans ^= who[i];        if(x.any()){ // 如果不为0, 那么输出0, 且把这个数加入矩阵作为一行            puts("0");            REP(i, lim) if(x[i]) {first[k] = i;break;}            row[k] = x;            who[k] = ans;            int p = k;            while(p && first[p]<first[p-1]){                swap(first[p], first[p-1]);                swap(who[p], who[p-1]);                swap(row[p], row[p-1]);                p --;            }        }else{ // 如果为0, 那么直接输出答案            printf("%d", ans.count()-1);            REP(i, k) if(ans.test(i)) printf(" %d", i);            puts("");        }    }    return 0;}



0 0
原创粉丝点击