JZOJ7038. 2021.04.01【2021省赛模拟】异或 (inception)题解

之前做过一道一模一样的题目
连数据范围都一样!!!
但自己还是没能想出那个结论!!!
结论:子序列中两两异或的最小值 > = x >=x >=x,这个最小值只可能在排序后相邻两项中取得。
也就是说对于 ∀ a ≤ b ≤ c , m i n ( a ⨁ b , b ⨁ c ) ≤ a ⨁ c \forall a\leq b\leq c,min(a\bigoplus b,b\bigoplus c)\leq a\bigoplus c abc,min(ab,bc)ac
等于的情况显然。
对于不等于的情况,考虑 a , b , c a,b,c a,b,c不全相等的最高位(二进制),设其值为 A , B , C A,B,C ABC
相等的话的 m i n ( a ⨁ b , b ⨁ c ) = a ⨁ c = 0 min(a\bigoplus b,b\bigoplus c)= a\bigoplus c=0 min(ab,bc)=ac=0
A ⨁ C = = 0 A\bigoplus C==0 AC==0时,即 A = C A=C A=C,有 A ≤ B ≤ C A\leq B\leq C ABC,那么 A = B = C A=B=C A=B=C,违反不全相等前提
因为 A ! = C A!=C A!=C,则 A ⨁ C = = 1 A\bigoplus C==1 AC==1
那么根据抽屉原理,必有 B = = A ∣ ∣ B = = C B==A||B==C B==AB==C,即 m i n ( a ⨁ b , b ⨁ c ) = = 0 min(a\bigoplus b,b\bigoplus c)==0 min(ab,bc)==0
结论得证
有了这个结论这题不就成trie裸题了?
f [ i ] f[i] f[i]为做到第 i i i个数的答案
f [ i ] = 1 + ∑ j = 1 i − 1 , ( a [ j ] ⨁ a [ i ] ≥ x ) f [ j ] {f[i]=1+\sum_{j=1}^{i-1,(a[j]\bigoplus a[i]\geq x)}f[j]} f[i]=1+j=1i1(a[j]a[i]x)f[j]
特判 x = 0 x=0 x=0的情况

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long 
#define mo 998244353
using namespace std;
ll i,j,k,m,n,o,p,l,s,t,lim,len,num;
ll trie[25000005][2],a[300005],sum[25000005],f[300005],bas[15000005];
void insert(ll t,ll pos,ll g,ll ad)
{
	sum[t]=0;
	if (pos==0) {
		bas[t]+=ad,bas[t]%=mo;sum[t]=bas[t];return;
	}
	ll h=g&(1ll<<(pos-1));
	if (!h)
	{
		if (!trie[t][0]) trie[t][0]=++len;
		insert(trie[t][0],pos-1,g,ad);
	} else {
		if (!trie[t][1]) trie[t][1]=++len;
		insert(trie[t][1],pos-1,g,ad); 
	}
	if (trie[t][0]) sum[t]+=sum[trie[t][0]],sum[t]%=mo;
	if (trie[t][1]) sum[t]+=sum[trie[t][1]],sum[t]%=mo;
}
ll query(ll t,ll pos,ll g)
{
	if (pos==0) return 0;
	ll h=g&(1ll<<(pos-1)),H=lim&(1ll<<(pos-1));
	if (!H)
	{
		ll s=0;
		if (!h)
		{
			if (trie[t][0]) s+=query(trie[t][0],pos-1,g),s%=mo;
			if (trie[t][1]) s+=sum[trie[t][1]],s%=mo;
		} else {
			if (trie[t][0]) s+=sum[trie[t][0]],s%=mo;
			if (trie[t][1]) s+=query(trie[t][1],pos-1,g),s%=mo;
		} 
		return s; 
	} else {
		ll s=0;
		if (!h)
		{
			if (trie[t][1]) s+=query(trie[t][1],pos-1,g),s%=998244353;
		} else {
			if (trie[t][0]) s+=query(trie[t][0],pos-1,g),s%=998244353;
		}
		return s;
	}
}
void read(ll &x)
{
	char ch=getchar();x=0;
	while (ch<'0'||ch>'9') ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-48,ch=getchar(); 
}
ll ksm(ll x,ll y)
{
	ll ans=1;
	for (;y;y>>=1,x=x*x%mo)
		if (y&1) ans=ans*x%mo;
	return ans;
}
int main()
{
	freopen("inception.in","r",stdin);
	freopen("inception.out","w",stdout);
	read(num),read(n),read(lim);
	if (lim==0) 
	{
		printf("%lld\n",ksm(2,n)-1);
		return 0;
	}
	if (lim) lim--;
	for (i=1;i<=n;i++) read(a[i]);
	sort(a+1,a+n+1),len=1;
	for (i=1;i<=n;i++) 
		f[i]=query(1,60,a[i])+1,
		insert(1,60,a[i],f[i]);
	ll ans=0;
	for (i=1;i<=n;i++) ans=(ans+f[i])%998244353; 
	printf("%lld\n",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值