GMOJ 6829. 2020.10.25提高组模拟异或
Posted mohogany
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}
以上是关于GMOJ 6829. 2020.10.25提高组模拟异或的主要内容,如果未能解决你的问题,请参考以下文章