【学习笔记】【集训队互测2015】最大异或和

这题大概有 N O I NOI NOI t 1 t1 t1难度。但是我维护的东西和正解恰好是反的啊啊啊

离线的做法太难想到了。注意到 n , m n,m n,m同阶,这看着非常亲切,因为意味着我们可以每次修改直接暴力维护,而不需要什么复杂度数据结构去平衡它。

将原序列差分,很容易想到维护一个支持插入,删除的线性基。我们不妨先给出算法流程,然后再来验证其复杂度。在 S A M SAM SAM中我们也是这么干的。

考虑用线性基维护,哪些数在线性基中,以及维护的每个线性基如何用它们表示,不在线性基中的数如何用基底表示。注意,这里的基底指的是原数。

然后分类讨论。设删除的数是 x x x,如果 x x x不是基底那么直接删除即可。否则如果存在 y y y不在基底中,并且其基底表示中有 x x x,那么就可以用 y y y来替代 x x x,显然基底张成的空间不变,那么线性基也不变,但是表示方式变了。如果不存在这样的 y y y,那么意味着基底的数目会减少 1 1 1,考虑消去 x x x对线性基的影响,但是注意到我们要保证最高位 1 1 1具有单调性,那么考虑找到最小的包含 x x x的线性基 z z z,这样 z z z向上消的时候最高位 1 1 1就不会发生变化,将线性基 z z z删除即可。因为是对原来的基进行线性变换所以剩下 k − 1 k-1 k1个线性基显然也是线性无关的。

复杂度 O ( n 3 w ) O(\frac{n^3}{w}) O(wn3)

#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
int n,m,Q,type,state[2005];
bitset<2005>base[2005],a[2005];
bitset<2005>bs[2005],bi[2005];
void add(int x){
    if(x>n||a[x]==a[x-1])return;
    bi[x].reset();
    state[x]=0;
    bitset<2005>tmp;
    tmp=a[x]^a[x-1];
    for(int i=0;i<m;i++){
        if(tmp[i]){
            if(base[i][i]){
                bi[x]^=bs[i];
                tmp^=base[i];
            }
            else{
                base[i]=tmp;
                bs[i]=bi[x];
                bs[i][x]=1;
                state[x]=1;
                return;
            }
        }
    }
}
void del(int x){
    if(x>n||a[x]==a[x-1])return;
    if(!state[x]){
        bi[x].reset();
        return;
    }
    bitset<2005>tmp;
    tmp=a[x]^a[x-1];
    for(int i=1;i<=n;i++){
        if(!state[i]&&bi[i][x]){
            bi[i][i]=1;
            state[i]=1;
            state[x]=0;
            bi[x].reset();
            for(int j=0;j<m;j++){
                if(bs[j][x]){
                    bs[j]^=bi[i];
                }
            }
            for(int j=1;j<=n;j++){
                if(!state[j]&&bi[j][x]){
                    bi[j]^=bi[i];
                }
            }
            return;
        }
    }
    int z=m-1;while(z>=0&&bs[z][x]==0)z--;
    for(int i=0;i<z;i++){
        if(bs[i][x]){
            bs[i]^=bs[z];
            base[i]^=base[z];
        }
    }
    base[z]=0;
    bs[z].reset();
    state[x]=0;
    bi[x].reset();
}
void query(){
    bitset<2005>tmp;
    for(int j=0;j<m;j++){
        if(base[j][j]&&!tmp[j]){
            tmp^=base[j];
        }
    }
    for(int j=0;j<m;j++)cout<<tmp[j];
    cout<<"\n";
}
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>n>>m>>Q;
    for(int i=1;i<=n;i++){
        string str;cin>>str;
        for(int j=0;j<m;j++){
            a[i][j]=str[j]-'0';
        }
    }
    for(int i=1;i<=n;i++){
        add(i);
    }
    for(int i=1;i<=Q;i++){
        int type;
        cin>>type;
        if(type==1){
           bitset<2005>tmp;
           int l,r;string str;
           cin>>l>>r>>str;
           for(int j=0;j<m;j++){
               tmp[j]=str[j]-'0';
           } 
           del(l),del(r+1);
           for(int j=l;j<=r;j++)a[j]^=tmp;
           add(l),add(r+1);
        }
        else if(type==2){
            bitset<2005>tmp;
            int l,r;string str;
            cin>>l>>r>>str;
            for(int j=0;j<m;j++){
                tmp[j]=str[j]-'0';
            }
            for(int j=l;j<=r+1;j++)del(j);
            for(int j=l;j<=r;j++)a[j]=tmp;
            add(l),add(r+1);
        }
        else if(type==3){
            query();
        }
    }
}
posted @ 2023-06-03 15:18  仰望星空的蚂蚁  阅读(46)  评论(0)    收藏  举报  来源