zoukankan      html  css  js  c++  java
  • 【luogu CF1100F】Ivan and Burgers

    Ivan and Burgers

    题目链接:luogu CF1100F

    题目大意

    给你一个序列,多次询问。
    每次问题序列第 l 个数到第 j 个数中,你可以选任意个异或起来,这个异或的最大值是多少。

    思路

    不难看到有这种各样的方法。
    我这里用的是比较优的纯线性基 (O(nlogn)) 做法。

    首先不难想到可有处理出 (1sim i) 的线性基,这个可以用像前缀和的方法搞到。
    但问题就是求 (jsim i) 的要怎么搞。
    容易想到,我们要让后面的数更多的放在线性基的数组中。

    那我们线性基不仅有数组 (d_i),还要有一个 (tim_i) 表示这是序列中的第几个数插进去的。
    那我们插入的时候,原本没有数就放进去,有的话就比较,如果现在插入的在后面,就 swap 一下,然后继续。
    swap 相当于把现在的数插进去,然后把之前插进入的拿出来,重新跟后面匹配。

    那这样,如果后面的可以自己组合替代前面的,那前面的就不会被放上去。
    那我们就可以对于 ([l,r]),我们查询 ([1,r]) 的线性基,如果它异或了更优而且时间在 (l) 之后或者是 (l) 我们再异或,这样得出来的答案就是 ([l,r]) 的答案了。

    代码

    #include<cstdio>
    #include<algorithm>
    
    using namespace std;
    
    int n, d[500001][21], tim[500001][21];
    int q, x, y;
    
    void add(int x, int y) {
    	int nt = x;
    	for (int i = 20; i >= 0; i--)
    		if ((y >> i) & 1) {
    			if (!d[x][i]) {
    				d[x][i] = y;
    				tim[x][i] = nt;
    				break;
    			}
    			if (nt > tim[x][i]) {//优先把时间后的放进去
    				swap(nt, tim[x][i]);
    				swap(d[x][i], y);
    			}
    			y ^= d[x][i];
    		}
    }
    
    int query(int x, int y) {
    	int re = 0;
    	for (int i = 20; i >= 0; i--)
    		if (tim[x][i] >= y && (re ^ d[x][i]) > re)//规定找在这个时间之后的
    			re ^= d[x][i];
    	return re;
    }
    
    int main() {
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i++) {
    		scanf("%d", &x);
    		for (int j = 0; j <= 20; j++)
    			d[i][j] = d[i - 1][j], tim[i][j] = tim[i - 1][j];
    		add(i, x);//搞出 1~i 的线性基(前缀和的感觉)
    	}
    	
    	scanf("%d", &q);
    	while (q--) {
    		scanf("%d %d", &x, &y);
    		printf("%d
    ", query(y, x));
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    curl crt
    test with nmap
    C#查询XML解决“需要命名空间管理器”问题
    Dapper实用教程
    javascript 计算两个日期的差值
    Glib学习笔记(二)
    安装osquery笔记
    Golang多线程简单斗地主
    PHP扩展开发之Zephir
    zabbix 安装记录
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/luogu_CF1100F.html
Copyright © 2011-2022 走看看