• 【题解】kth异或和/魔改版线性基


    【题解】魔改版线性基

    魔改版线性基解决此类问题。

    联系线性空间的性质,我们直接可以构造出这样的基:

    [100000 \ 010000 \ 000010 \ 000001 ]

    使得每个基的最高位是唯一的,我们的目的是要能够保证从上往下一直异或一直变大,所以不能使基出现这样的情况:

    [100001 \ 000001 ]

    一个不能从上往下一直异或一直变大的例子。

    考虑如何构造(kth) 大(小),考虑这样的性质,我们记(a_i)表示从下往上第(i)个基,显然从(0)开始,如果我们异或了(a_x),那么我们可以保证我们会比这个线性空间内(2^{x-1})个值都要大,直接考虑从上往下查询,类似树上倍增。

    考虑无解的情况,显然当我们发现(k ge 2^{|E|})时就无解了。

    然而我们有一个问题,那就是我们默认(0)是可以被表示出来的,然而我们知道,当给定元素全部互为不相关时,这个时候就不存在一个(0)会被表示出来了。那么我们可以特判一下即可 。

    好,那么如何构造从上往下一直异或一直变大的基呢?魔改一下就好了。具体看代码。

    分析复杂度:我们把魔改操作的(log^2)看做常数吧...那就是(O(nlogn))

    当然你如果不承认魔改操作是常数,那就继续魔改(upd)函数,也可以做到(nlogn)。具体就是加入的时候从小往大加。

    下面的第(k)小,转换为第(k)大用(2^{|E|}​)减去即可。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    template <class ccf>
    inline ccf qr(ccf ret) {
          ret = 0;
          register char c = getchar();
          while (c < 48 || c > 57) c = getchar();
          while (c >= 48 && c <= 57) ret = ret * 10 + c - 48, c = getchar();
          return ret;
    }
    namespace bs {
          ll num[51], sav[51];
          struct BASE {
    	    ll data[51];
    	    int cnt;
    	    ll p;
    	    BASE() {
    		  memset(data, 0, sizeof data);
    		  cnt = 0;
    		  p = 1;
    	    }
    	    inline ll size() { return 1LL << cnt; }
    	    inline void set() {
    		  for (register int t = 1; t <= 50; ++t)
    			if (data[t])
    			      for (register int i = t + 1; i <= 50; ++i)
    				    if (data[i] & num[t])
    					  data[i] ^= data[t];
    	    }
    	    inline void upd(ll x) {
    		  for (register int t = 50; t >= 1; --t) {
    			if (x & num[t]) {
    			      if (not data[t]) {
    				    data[t] = x;
    				    ++cnt;
    				    break;
    			      } else
    				    x ^= data[t];
    			}
    			if(not x) {
    			      p=0;
    			      break;
    			} 
    		  }
    	    }
    	    inline ll que(ll k) {
    		  register ll ret = 0, sav = 0;
    		  if(cnt==50) --k; 
    		  if (k > this->size())
    			return -1;
    		  for (register int t = 50, f = 0; t >= 1; --t) {
    			if (data[t]) {
    			      ++f;
    			      if (sav + (1LL << (cnt - f)) <= k)
    				    sav += 1LL << (cnt - f), ret = ret ^ data[t];
    			}
    		  }
    		  return ret;
    	    }
    	    inline void clear() {
    		  memset(data, 0, sizeof data);
    		  cnt = 0;
    	    }
    	    inline void debug() {
    		  for (register int t = 50; t >= 1; --t) {
    			if (data[t])
    			      cout << ((bitset<10>)data[t]) << ' ' << data[t] << endl;
    		  }
    		  cout << endl;
    	    }
          };
          inline void init() {
    	    for (num[0] = 2, num[1] = 1; num[0] <= 50; ++num[0]) num[num[0]] = num[num[0] - 1] << 1;
          }
    }
    bs::BASE qaq;
    
    int main() {
          bs::init();
          int n = qr(1);
          for (register int t = 1; t <= n; ++t) qaq.upd(qr(1ll));
          int m = qr(1);
          qaq.set();
          for (register int t = 1; t <= m; ++t) printf("%lld
    ", qaq.que(qr(1ll)));
          return 0;
    }
    
    
  • 相关阅读:
    《网络攻防与实践》第九周学习
    《网络攻防技术与实践》第八周作业
    《网络攻击技术与实践》第七周作业
    《网络攻防技术与实践》第六周学习
    《网络攻防技术与实践》第五周作业
    《网络攻防技术与实践》第四周学习
    《网络攻防技术与实践》第三周学习总结
    《网络攻防技术与实践》第二周学习总结
    20169214 2016-2017-2 《网络攻防实践》第十一周实验 SQL注入
    20169214 2016-2017-2 《移动平台开发实践》Android程序设计 实验报告
  • 原文地址:https://www.cnblogs.com/winlere/p/10602810.html
Copyright © 2020-2023  润新知