题意:n个数里找到三个数,使得( a[ i ] + a[ j ] ) ^ a[ k ] 最大。(i, j, k互不相同)
思路:首先考虑到时间最大是 5s ,然后 n 最大是4000,所以我们最大的复杂度是n ^ 2 * log n,所以我们可以直接跑二层循环找相加的两个数,然后用字典树来找异或最大的数。
【字典树的删除操作】
因为我们要保证三个数不相同,所以我们要将a[ i ] 和 a[ j ]从字典树里删除掉,然后再找a[ k ]。
我们需要注意的就是删除操作怎么实现?
首先我们用一个cnt数组来存该结点有多少个子节点。如果我们直接从中间将树一分为二(也就是Delete的时候遇到 - - cnt[ ] 为0的时候就直接return,并且用tire[ ][ ] = 0 截断了这颗树,后面的结点不管),因为再次插入数值的时候tot是直接开辟新空间的,那么我们的空间消耗是很大的。
所以我们采用将所有该数值的32位所在的结点全部 cnt 减一,但是不截断这棵树。这样的话我们Insert的时候tot就不会额外的增加。需要注意的是查找的时候要判断一下tire[ rt ] [ id ^ 1 ] && cnt[ tire[ rt ] [ id ^ 1] ] > 0,树上有我们要找的数值,并且该结点存在(因为我们可能删除了还没有插入回来)。
这样的的话就解决了问题。
其实val是不需要初始化的,因为Insert的时候,会重新赋值并且Search的时候只会用到该次样例下赋过值的,所以之前用过的也不影响。
2731 MS 2000 KB
这里是每用一个tire 和 cnt 数组空间清零一个。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxN= 2e5 ;
int n, a[maxN], tire[maxN][2], cnt[maxN], val[maxN], tot;
void init()
{
tot = 0;
cnt[0] = 0;
for(int i = 0; i < 2 ; i++)
tire[0][i] = 0;
}
void Clear(int rt)
{
for(int i = 0; i < 2 ; i++)
tire[rt][i] = 0;
cnt[rt] = 0;
}
void Insert(int x)
{
int rt = 0;
for(int i = 31; i >= 0 ; i --)
{
int id = (x >> i) & 1;
if(!tire[rt][id])
{
tire[rt][id] = ++tot;
Clear(tot);
}
cnt[ tire[rt][id] ] ++;
rt = tire[rt][id];
}
val[rt] = x;
}
void Delete(int x)
{
int rt = 0;
for(int i = 31; i >= 0; i -- )
{
int id = (x >> i) & 1;
-- cnt[ tire[rt][id] ];
rt = tire[rt][id];
}
}
int Search(int x)
{
int rt = 0;
for(int i = 31; i >= 0; i --)
{
int id = (x >> i) & 1;
if(tire[rt][id ^ 1] && cnt[ tire[rt][id ^ 1] ] > 0)
rt = tire[rt][id ^ 1];
else
rt = tire[rt][id];
}
return val[rt];
}
int main()
{
while(~scanf("%d", &n))
{
init();
for(int i = 1 ; i <= n ; i++)
{
scanf("%d", &a[i]);
Insert(a[i]);
}
int ans = 0;
for(int i = 1 ; i <= n ; i++)
{
Delete(a[i]);
for(int j = i+1 ; j <= n ; j++)
{
int sum = a[i] + a[j];
Delete(a[j]);
int tmp = Search(sum);
ans = max(ans, tmp ^ sum);
Insert(a[j]);
}
Insert(a[i]);
}
printf("%d\n", ans);
}
return 0;
}
2869 MS 3608 KB
这个就是不用memset,用多少n,初始化多少数组
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxN= 2e5 ;
int n, a[maxN], tire[maxN][2], cnt[maxN], val[maxN], tot;
void init()
{
for(int i = 0 ; i<= 32 * n ; i++)
{
val[i] = 0;
cnt[i] = 0;
memset(tire[i], 0, sizeof(tire[i]));
}
tot = 0;
}
void Insert(int x)
{
int rt = 0;
for(int i = 31; i >= 0 ; i --)
{
int id = (x >> i) & 1;
if(!tire[rt][id])
tire[rt][id] = ++tot;
cnt[ tire[rt][id] ] ++;
rt = tire[rt][id];
}
val[rt] = x;
}
void Delete(int x)
{
int rt = 0;
for(int i = 31; i >= 0; i -- )
{
int id = (x >> i) & 1;
-- cnt[ tire[rt][id] ];
rt = tire[rt][id];
}
}
int Search(int x)
{
int rt = 0;
for(int i = 31; i >= 0; i --)
{
int id = (x >> i) & 1;
if(tire[rt][id ^ 1] && cnt[ tire[rt][id ^ 1] ] > 0)
rt = tire[rt][id ^ 1];
else
rt = tire[rt][id];
}
return val[rt];
}
int main()
{
while(~scanf("%d", &n))
{
init();
for(int i = 1 ; i <= n ; i++)
{
scanf("%d", &a[i]);
Insert(a[i]);
}
int ans = 0;
for(int i = 1 ; i <= n ; i++)
{
Delete(a[i]);
for(int j = i+1 ; j <= n ; j++)
{
int sum = a[i] + a[j];
Delete(a[j]);
int tmp = Search(sum);
ans = max(ans, tmp ^ sum);
Insert(a[j]);
}
Insert(a[i]);
}
printf("%d\n", ans);
}
return 0;
}
3022 MS 4720 KB
这个就是直接用memset初始化。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxN= 2e5 ;
int n, a[maxN], tire[maxN][2], cnt[maxN], val[maxN], tot;
void init()
{
memset(val, 0, sizeof(val));
memset(tire, 0, sizeof(tire));
memset(cnt, 0, sizeof(cnt));
tot = 0;
}
void Insert(int x)
{
int rt = 0;
for(int i = 31; i >= 0 ; i --)
{
int id = (x >> i) & 1;
if(!tire[rt][id])
tire[rt][id] = ++tot;
cnt[ tire[rt][id] ] ++;
rt = tire[rt][id];
}
val[rt] = x;
}
void Delete(int x)
{
int rt = 0;
for(int i = 31; i >= 0; i -- )
{
int id = (x >> i) & 1;
-- cnt[ tire[rt][id] ];
rt = tire[rt][id];
}
}
int Search(int x)
{
int rt = 0;
for(int i = 31; i >= 0; i --)
{
int id = (x >> i) & 1;
if(tire[rt][id ^ 1] && cnt[ tire[rt][id ^ 1] ] > 0)
rt = tire[rt][id ^ 1];
else
rt = tire[rt][id];
}
return val[rt];
}
int main()
{
while(~scanf("%d", &n))
{
init();
for(int i = 1 ; i <= n ; i++)
{
scanf("%d", &a[i]);
Insert(a[i]);
}
int ans = 0;
for(int i = 1 ; i <= n ; i++)
{
Delete(a[i]);
for(int j = i+1 ; j <= n ; j++)
{
int sum = a[i] + a[j];
Delete(a[j]);
int tmp = Search(sum);
ans = max(ans, tmp ^ sum);
Insert(a[j]);
}
Insert(a[i]);
}
printf("%d\n", ans);
}
return 0;
}