zoukankan      html  css  js  c++  java
  • GMOJ 6829. 【2020.10.25提高组模拟】异或

    这是这场比赛第二水的一题,但我并没有切。

    题解:

    正解其实很简单,很容易可以发现一个性质,讲一个序列排序,xor值最小的值肯定出现在相邻两个数之间,
    证明:设a<b<c,那么我们只需要证明min(ab,bc)<a^c设到第t位开始第一次出现a,b,c在第t位上的值不同,有两种情况:
    1.(0,0,1) 此时ab<ac
    2. (0,1,1) 此时bc>ac
    综上所述,xor值最小的值肯定出现在相邻两个数之间。
    有了这个性质,我们就很容易可以想出正解:
    我们设f[i]表示以i结尾的序列个数,那么我们有f[i]=sigma(f[j] (a[i]^a[j]>=x) )+1。
    这个转移可以用trie来优化。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 500000
    #define K 63
    #define ll long long
    #define mo 998244353
    using namespace std;
    ll n,X,a[N],i,f[N],ans,num;
    struct trie{
    	ll sum,s[2];
    }tr[N*K];
    void insert(ll x,ll s,ll val,ll t){
    	if (t>K){
    		tr[x].sum+=val;
    		return;
    	}
    	ll p=s>>(K-t);
    	if (!tr[x].s[p&1]) tr[x].s[p&1]=++num;
    	insert(tr[x].s[p&1],s,val,t+1);
    	tr[x].sum=tr[tr[x].s[0]].sum+tr[tr[x].s[1]].sum;
    }
    ll get(ll x,ll s,ll t,ll X){
    	if (!x) return 0;
    	ll p=(s>>(K-t))&1,val=1ll<<(K-t),sum=0;
    	if (val>=X) sum+=tr[tr[x].s[1-p]].sum,sum%=mo;
    	if (val>X) sum+=get(tr[x].s[p],s,t+1,X),sum%=mo;
    	if (val<X) sum+=get(tr[x].s[1-p],s,t+1,X-val),sum%=mo;
    	return sum;
    }
    int main(){
    	freopen("xor.in","r",stdin);
    	freopen("xor.out","w",stdout);
    	scanf("%lld%lld",&n,&X);
    	for (i=1;i<=n;i++) scanf("%lld",&a[i]);
    	sort(a+1,a+n+1);
    	num=1;
    	for (i=1;i<=n;i++){
    		f[i]=1+get(1,a[i],1,X);
    		ans=(ans+f[i])%mo;
    		insert(1,a[i],f[i],1);
    	}
    	printf("%lld
    ",ans%mo);
    	return 0;
    }
    
  • 相关阅读:
    35个Java代码优化的细节,你知道几个?
    Java如何优雅地实现接口数据校验
    Java中方法的重载详解(含系统配套视频)
    七大经典、常用排序算法的原理、Java 实现以及算法分析
    Java静态方法和实例方法
    Java静态变量和实例变量
    “反转链表”相关的题目
    【C++】将十进制数转换为十六进制数
    第四章:动态规划I
    【C++】数组中的第k个最小元素
  • 原文地址:https://www.cnblogs.com/Mohogany/p/13887292.html
Copyright © 2011-2022 走看看