码迷,mamicode.com
首页 > 其他好文 > 详细

GMOJ 6829. 【2020.10.25提高组模拟】异或

时间:2020-10-31 01:40:27      阅读:17      评论:0      收藏:0      [点我收藏+]

标签:get   提高   lld   str   png   但我   scanf   define   string   

技术图片

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

题解:

正解其实很简单,很容易可以发现一个性质,讲一个序列排序,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\n",ans%mo);
	return 0;
}

GMOJ 6829. 【2020.10.25提高组模拟】异或

标签:get   提高   lld   str   png   但我   scanf   define   string   

原文地址:https://www.cnblogs.com/Mohogany/p/13887292.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!