• 2019杭电多校训练第二场1002


    https://vjudge.net/problem/HDU-6579

    题意:

    给出n个数,接下来有m次操作。

    1   k:在数组后面多加一个k。(n=n+1)。

    0  l   r:询问[l,r]区间内任意取数,异或和的最大值。

    特别要注意的是2种操作都加密了,1号操作需要k=k^lasten;2号操作需要l=(l^lasten)%n+1,r=(r^lasten)%n+1.lasten初始值为0,以后lasten为上一次0号操作的答案。

    思路:

    前缀线性基。建立二维数组pre_p[1000009][maxbit],表示从1~i前i个数组成的线性基。建立数组pre_pos[1000009][maxbit],表示对于第i个前缀线性基第j位为1的数的最大下标(另一种理解: 对于区间[1,i]内的数,二进制第j位为1的最大下标。可能是由不止一个数异或而成的,此时记录这几个数的最小下标)。

    对于每一次1号操作,都要在重新维护pre_p数组和pre_pos数组。

    对于0号操作,我们按普通的线性基用法使用pre_p[r],不同的就是对于每一个不为0的pre_p[r][j]都要判断pre_pos[r][j]>=l是否成立。即当右端点固定为r时,pre[r][j]是否可以在l以后出现。

    (本人原本maxbit开的是32,然后一直血wa,换成31就过了,血的教训)

    #include<bits/stdc++.h>
    using namespace std;
    const int maxbit=31;
    #define met(a,b) memset(a,b,sizeof(a))
    int p[maxbit+5],pos[maxbit+5],pre_p[1000009][maxbit],pre_pos[1000009][maxbit];
    void solve(int val,int adr )//建立1~adr的前缀线性基
    {
        int k=adr;
        for(int i=maxbit-1; i>=0; i--)
        {
            if((val>>i)&1)//
            {
                if(!p[i])
                {
                   // cout<<(val>>i)<<endl;
                   // cout<<i<<"__________ "<<p[i]<<"....."<<val<<endl;
                    p[i]=val;
                    pos[i]=adr;
                    break;
                 }
                else
                {
                    if(pos[i]<adr)swap(p[i],val),swap(adr,pos[i]);//本题重点代码,更新二进制第i为1的下标
                    val^=p[i];//新的val是原val与原p[i]异或得到的,所以adr应该是2者较小的下标(即原p[i]的下标),所以上面用swap而不是赋值。
                }
            }
        }
        for(int i=0; i<=maxbit-1; ++i)
        {
            pre_p[k][i]=p[i];
            pre_pos[k][i]=pos[i];
        }
    }
    int seek_ans(int l,int r)//在区间[l,r]内搜寻答案
    {
        if(l>r) swap(l,r);
        int k=0;
        for(int i=maxbit-1; i>=0; i--)
        {
            if(pre_p[r][i] &&pre_pos[r][i]>=l)
                k=max(k,k^pre_p[r][i]);
        }
        return k;
    }
    int main()
    {
        std::ios::sync_with_stdio(false);
        std::cin.tie(0);
        std::cout.tie(0);
        int T;
        cin>>T;
        while(T--)
        {
            int n,m,k;
            cin>>n>>m;
            for(int i=1; i<=n; i++)
            {
                cin>>k;
                solve(k,i);
            }
            int lastans=0;
            for(int t=0; t<m; t++)
            {
                int f;
                cin>>f;
                if(f)
                {
                    cin>>k;
                    k^=lastans;//解密
                    solve(k,++n);//建立线性基
                }
                else
                {
                    int l,r;
                    cin>>l>>r;
                    lastans=seek_ans((l^lastans)%n+1,(r^lastans)%n+1);//解密找答案
                    cout<<lastans<<endl;
                }
            }
            for(int j=maxbit-1;j>=0;--j) p[j]=pos[j]=0;//初始化
            for(int i=0;i<=n;i++)
            {
                for(int j=maxbit-1;j>=0;--j)
                    pre_p[i][j]=pre_pos[i][j]=0;
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    [PY3]——logging
    [PY3]——对iterator的处理(解析式、map、reduce、filter)
    php基础语法(文件加载和错误)
    php基础语法(控制语句、数组、函数)
    php基础语法(数据类型、运算符)
    php基础语法(变量)
    java基础语法
    ztree 获取根节点
    每天一个linux命令
    浅谈Web自适应
  • 原文地址:https://www.cnblogs.com/yzxqq/p/11251680.html
Copyright © 2020-2023  润新知