zoukankan      html  css  js  c++  java
  • 洛谷.5283.[十二省联考2019]异或粽子(可持久化Trie 堆)

    LOJ
    洛谷

    考场上都拍上了,8:50才发现我读错了题=-=
    两天都读错题...醉惹...


    (Solution1)
    先求一遍前缀异或和。
    假设左端点是(i),那么我们要在([i,n])中找一个(sum_j)使得它和(sum_{i-1})异或最大。可以可持久化Trie。
    (iin[1,n])都求一遍它能得到的最大的异或值,扔到堆里。
    每次从堆里找出值最大的,假设是(x),与(sum_{x-1})异或得到最大值的数是(sum_y),那么之后就不能选(sum_{x-1} mathbb{xor} sum_y)了。
    (T_i)为第(i)(Trie)。因为查询最大值时,我们是用(T_n)(T_{i-1})(size)差是否(>0),来判断能否取一个值。
    所以现在令(T_{x-1})(sum_y)这条路径上的(size+1),就可以实现删掉一个(sum_y)了。
    修改(T_{x-1})之后再找一个和(sum_{x-1})异或最大的,把(x)扔到堆里。
    这个(Modify)(Insert)函数一模一样(考场上我竟然没注意到这个=-=)。

    (Solution2)
    (sum_i ^{wedge}sum_j=sum_j ^{wedge}sum_i),所以可以把(k)变成(2k),求任意一对数异或,能得到的最大的(k)对是多少。
    对每个数求一下和它异或最大的是哪个,扔到堆里。
    每次从堆里取出值最大的一个数(i),加上(i)的答案。然后我们要找,和(sum_i)异或第二大的值是哪个。在(Trie)上查即可。再扔到堆里。再下一次就查,和(sum_i)异或第(3)大的值是哪个...
    对所有数建一棵(Trie)即可。

    (Solution3)
    有一种类似[NOI2010]超级钢琴的做法。


    代码是考场上的代码,有点丑,但也没什么改的必要了...

    #include <queue>
    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    //#include <unordered_map>
    #define mp std::make_pair
    #define pr std::pair<uint,int>
    #define BIT 31
    //#define gc() getchar()
    #define MAXIN 300000
    #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    typedef unsigned int uint;
    typedef long long LL;
    typedef unsigned long long ull;
    const int N=5e5+5;
    
    int root[N];
    uint A[N],sum[N];
    std::priority_queue<pr> q;
    //std::mt19937 Rand(1002330);
    char IN[MAXIN],*SS=IN,*TT=IN;
    struct Trie
    {
    	#define S N*(BIT+2)*2
    	int tot,son[S][2],sz[S];
    	void Insert(int &rt,int y,uint v)
    	{
    		int x=rt=++tot;
    		for(int i=BIT; ~i; --i)
    		{
    			int c=v>>i&1;
    			son[x][c^1]=son[y][c^1];
    			x=son[x][c]=++tot, y=son[y][c], sz[x]=sz[y]+1;
    		}
    	}
    	uint Query(int x,int y,uint v)//y-x
    	{
    		uint res=0;
    		for(int i=BIT; ~i; --i)
    		{
    			int c=(v>>i&1)^1;
    			if(sz[son[y][c]]-sz[son[x][c]]>0) res|=1u<<i;
    			else c^=1;
    			x=son[x][c], y=son[y][c];
    		}
    		return res;
    	}
    	void Modify(int &rt,int X,uint v)
    	{
    		int x=rt=++tot;
    		for(int i=BIT; ~i; --i)
    		{
    			int c=(v>>i&1);
    			son[x][c^1]=son[X][c^1];
    			x=son[x][c]=++tot, X=son[X][c], sz[x]=sz[X]+1;
    		}
    	}
    }T;
    
    inline uint read()
    {
    	uint now=0; register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-48,c=gc());
    	return now;
    }
    namespace Subtask1
    {
    	uint q[4000005];
    	void Main(int n,int K)
    	{
    		int t=0;
    		for(int i=1; i<=n; ++i)
    		{
    			uint now=0;
    			for(int j=i; j<=n; ++j)
    				now^=A[j], q[++t]=now;
    		}
    		std::sort(q+1,q+1+t,std::greater<uint>());
    		LL ans=0;
    		for(int i=1; i<=t&&i<=K; ++i) ans+=q[i];
    		printf("%I64d
    ",ans);
    	}
    }
    
    int main()
    {
    	freopen("xor.in","r",stdin);
    	freopen("xor.out","w",stdout);
    
    	int n=read(),K=read();
    	for(int i=1; i<=n; ++i) A[i]=read(),sum[i]=A[i]^sum[i-1];
    //	if(n<=2000) return Subtask1::Main(n,K),0;
    	for(int i=1; i<=n; ++i) T.Insert(root[i],root[i-1],sum[i]);
    	for(int i=1; i<=n; ++i) q.push(mp(T.Query(root[i-1],root[n],sum[i-1]),i));
    	LL ans=0;
    	while(K--&&!q.empty())
    	{
    		uint tmp=q.top().first; ans+=tmp;
    		int x=q.top().second; q.pop();
    		T.Modify(root[x-1],root[x-1],tmp^sum[x-1]);
    		q.push(mp(T.Query(root[x-1],root[n],sum[x-1]),x));
    	}
    	printf("%I64d
    ",ans);
    
    	return 0;
    }
    
  • 相关阅读:
    关于掌握C#的内存堆栈概念
    sqlserver 跨服务器查询
    写单元测试的知识结构(2)——单元测试工具的选用(找个顺手的)
    写单元测试的知识结构(1) —— 单元测试用处
    如何能保证自己的功能代码不出纰漏
    Mysql查询架构信息
    Mysql 分组查询最高分
    Mysql按照字段值做分组行转列查询
    软件测试学习笔记:主路径测试
    软件测试学习笔记:Junit入门
  • 原文地址:https://www.cnblogs.com/SovietPower/p/10673040.html
Copyright © 2011-2022 走看看