• CF1261F XorSet


    一、题目

    点此看题

    二、解法

    从计算答案的角度入手,我们不能逐个数地考虑它们能否构造出来,但是以防算重我们需要以异或结果的数为主体来考虑,建议给出的数是区间的形式,那么我们考虑一段一段地考虑数

    具体来说我们需要利用拆位的思想,我们将给定的区间分解成 \([k\cdot 2^y,(k+1)\cdot 2^y)\) 的形式,也就是后面 \(y\) 位是从 \(00..00\)\(11..11\) 的全排列,那么任意两个拆位后的区间异或之后得到的结果还是区间,因为前面的位都是直接异或的结果,后面的位得到的是全排列。

    可以把原区间丢到权值线段树上完成拆分的操作,但是枚举两两配对会得到 \(O(n^2\log^2 a)\) 个区间,再对这些区间求并显然复杂度爆炸,需要进一步优化。

    观察到上面的求并是有很多无效操作的,也就是对于两个长度分别为 \(2^A,2^B(A>B)\) 的区间,后 \(A\) 位都显示为全排列,所以很多 \(B\) 不同的区间也会有相同的效果。那么我们把长度为 \(B\) 的扩充成 \(A\),尝试把多次合并成一次做。

    扩充长度对应到线段树上就是跳父亲,那么优化考虑只做线段树上深度相同的区间,也就是对于第一个序列我们把区间放在线段树的终止节点上,第二个序列则把区间放在线段树经过的所有节点上,先做一遍再对换过来即可。

    时间复杂度 \(O(n^2\log a)\)

    //My heart travels at the speed of light
    #include <cstdio>
    #include <vector>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int M = 100005;
    #define pb push_back
    #define int long long
    const int inf = (1ll<<60)-1;
    const int MOD = 998244353;
    const int inv2 = (MOD+1)/2;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,ans,cnt,rt,ls[M],rs[M];
    struct node
    {
    	int l,r;
    	bool operator < (const node &b) const
    	{
    		if(l==b.l) return r<b.r;
    		return l<b.l;
    	}
    }a[M],b[M];
    vector<node> p[70],q[70],v;
    void add1(int &x,int l,int r,int L,int R,int d)
    {
    	if(!x) x=++cnt,p[d].pb(node{l,r});
    	if(L<=l && r<=R) return ;
    	int mid=(l+r)>>1;
    	if(L<=mid) add1(ls[x],l,mid,L,R,d+1);
    	if(R>mid) add1(rs[x],mid+1,r,L,R,d+1);
    }
    void add2(int l,int r,int L,int R,int d)
    {
    	if(L<=l && r<=R) {q[d].pb(node{l,r});return ;}
    	int mid=(l+r)>>1;
    	if(L<=mid) add2(l,mid,L,R,d+1);
    	if(R>mid) add2(mid+1,r,L,R,d+1);
    }
    void solve()
    {
    	for(int i=1;i<=cnt;i++) ls[i]=rs[i]=0;
    	for(int i=0;i<=60;i++) p[i].clear(),q[i].clear();
    	cnt=rt=0;
    	for(int i=1;i<=n;i++) add1(rt,0,inf,a[i].l,a[i].r,0);
    	for(int i=1;i<=m;i++) add2(0,inf,b[i].l,b[i].r,0);
    	for(int w=0;w<=60;w++)
    		for(auto x:p[w]) for(auto y:q[w])
    		{
    			int low=y.l^y.r;
    			v.pb(node{(x.l^y.l)&(~low),(x.l^y.l)|low});
    		}
    }
    int calc(int l,int r)
    {
    	return ((l+r)%MOD)*((r-l+1)%MOD)%MOD*inv2%MOD;
    }
    signed main()
    {
    	n=read();
    	for(int i=1;i<=n;i++)
    		a[i].l=read(),a[i].r=read();
    	m=read();
    	for(int i=1;i<=m;i++)
    		b[i].l=read(),b[i].r=read();
    	solve();swap(n,m);swap(a,b);solve();
    	if(v.empty()) {puts("0");return 0;}
    	sort(v.begin(),v.end());int l=0,r=0;
    	for(auto x:v)
    	{
    		if(x.l<=r+1) r=max(r,x.r);
    		else ans=(ans+calc(l,r))%MOD,l=x.l,r=x.r;
    	}
    	ans=(ans+calc(l,r))%MOD;
    	printf("%lld\n",ans);
    }
    
  • 相关阅读:
    连接心跳问题
    超时时间已到
    CSS定位属性-position
    AJAX背景技术介绍
    mysql中length字符长度函数使用方法
    mysql常用函数
    php构造函数的继承方法
    属性选择器(通常用在input)
    input标签常用属性
    PHP程序如何debug?
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15799307.html
Copyright © 2020-2023  润新知