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;
}

感谢观看!