0%

[湖北省选模拟2024] 花神诞日

你说得对。

但是我凭借超强的挂分能力,成功在这场比赛中拿到了个位数的好成绩。

题目链接

题意

现在有 种食材,第 种食材的味道是

你现在要用这些食材做成两道菜,每一种食材必须恰好用于一道菜,每一道菜至少拥有一种食材。

两种食材若被用在一道菜里,则会发生反应,食材 与食材 反应会产生 的味道。

一道菜的味道是所有食材两两反应得到味道的最小值。

现在要求第一道菜味道不低于 ,第二道菜味道不低于 ,求总方案数。

题解

场上根本不知道这题该咋想,只会 分,做题太少导致的。

首先注意到,一道菜的味道,是所有食材两两异或的最小值。

这里就牵扯到一个经典结论了。

就是对于一个有序数组,两两异或的最小值,一定是某两个相邻元素的异或。

证明很简单,只需要对于 证明 即可。

时,显然成立。

否则, 的最高位不同,设其为第 位。

,而 必然恰有一个 ,证明完毕。

好,既然有了这个结论,我们就只需要先将整个数组排序,然后只关注两道菜中的相邻元素的异或值是否满足要求。

表示前 种食材中,第一道菜的最后一个食材是 ,第二道菜的最后一个食材是 ,满足条件方案数是多少。

同理可以定义

这样就可以 完成这道题,拿到 分。

使用字典树优化转移即可。

复杂度

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3fll
#define debug(x) cerr<<#x<<"="<<x<<endl
using namespace std;
const int mod=1000000007;
using ll=long long;
using ld=long double;
using pli=pair<ll,int>;
using pi=pair<int,int>;
template<typename A>
using vc=vector<A>;
inline int read()
{
int s=0,w=1;char ch;
while((ch=getchar())>'9'||ch<'0') if(ch=='-') w=-1;
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
inline ll lread()
{
ll s=0,w=1;char ch;
while((ch=getchar())>'9'||ch<'0') if(ch=='-') w=-1;
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
ll num[25000001];
int ls[25000001];
int rs[25000001];
ll a[200001];
int r1,r2;
ll k1,k2;
int cnt;
ll mi=inf;
int n;
ll get(int p,int dep,ll v,ll lim)
{
if(!p) return 0;
if(dep==-1) return num[p];
if((lim>>dep)&1)
{
if((v>>dep)&1) return get(ls[p],dep-1,v,lim);
return get(rs[p],dep-1,v,lim);
}
else
{
if((v>>dep)&1) return num[ls[p]]+get(rs[p],dep-1,v,lim);
return num[rs[p]]+get(ls[p],dep-1,v,lim);
}
}
void ins(int &p,int dep,ll x,ll y)
{
if(!p) p=++cnt;
num[p]+=y;if(num[p]>=mod) num[p]-=mod;
if(dep==-1) return ;
if((x>>dep)&1) ins(rs[p],dep-1,x,y);
else ins(ls[p],dep-1,x,y);
}
int main()
{
n=read(),k1=lread(),k2=lread();
for(int i=1;i<=n;i++) a[i]=lread();
sort(a+1,a+n+1,[](ll a,ll b){ return a<b;});
for(int i=1;i<=n;i++)
{
ll v1=get(r1,59,a[i],k2)%mod;
ll v2=get(r2,59,a[i],k1)%mod;
if((a[i-1]^a[i])<k1) r1=0;
if((a[i-1]^a[i])<k2) r2=0;
if(i>=2)
{
ins(r2,59,a[i-1],v1+(mi>=k1));
ins(r1,59,a[i-1],v2+(mi>=k2));
mi=min(mi,a[i-1]^a[i]);
}
}
printf("%lld\n",(num[r1]+num[r2])%mod);
return 0;
}

感谢观看!