D e s c r i p t i o n \mathcal{Description} Description
S o l u t i o n \mathcal{Solution} Solution
有两种方法都可以拿到满分
S o l u t i o n 1 Solution\ 1 Solution 1
考虑枚举
y
y
y
建两个
01
T
r
i
e
01Trie
01Trie,要支持删除操作
一颗
T
r
i
e
Trie
Trie维护
y
y
y左边的信息
一颗
T
r
i
e
Trie
Trie维护
y
y
y右边的信息
在枚举
y
y
y的时候左边的添加,右边的删除,可做到
l
o
g
log
log维护,建树是
n
l
o
g
nlog
nlog
暴力的想法是两个
T
r
i
e
Trie
Trie一起跑,枚举在哪一位开始不一样,前面的情况也都枚举,这样的情况最坏是
2
2
2的指数级别,可以拿到
50
50
50分
考虑优化这个过程
因为每次只会删去一条链,所以考虑这条链被删去所带来的影响
用
f
[
i
]
[
0
/
1
]
f[i][0/1]
f[i][0/1]表示到第
i
i
i位开始不一样的答案
每次删除时只少了一条链,所以把这条链的情况减去
增加时加上新的情况即可
S o l u t i o n 2 Solution\ 2 Solution 2
这种方法相对来说代码量要少很多
考虑枚举
z
z
z
用一颗
T
i
r
e
Tire
Tire表示前面的信息
仍然考虑枚举在哪一位开始不一样
(
d
)
(d)
(d)
记
s
[
i
]
[
0
/
1
]
s[i][0/1]
s[i][0/1]表示前面所有在第
i
i
i位为
0
/
1
0/1
0/1的串的总数
记
s
u
m
[
i
]
sum[i]
sum[i]表示
T
i
r
e
Tire
Tire上
i
i
i号节点有多少个不合法的
(
x
,
y
)
(x,y)
(x,y)对
(
y
<
x
)
(y<x)
(y<x)
记
c
n
t
[
i
]
cnt[i]
cnt[i]表示
T
i
r
e
Tire
Tire上经过
i
i
i的个数
由于枚举的是
z
z
z,我们对
y
y
y的要求只有 枚举到
d
d
d时,其在
d
d
d是
0
0
0还是
1
1
1
假设枚举到的
z
z
z的值在
d
d
d位是
c
c
c
答案就是cnt[原本串中和
z
z
z的
d
d
d前面的位相同]
×
s
[
d
]
[
!
c
]
−
\times s[d][!c]-
×s[d][!c]−不合法的
(
x
,
y
)
(x,y)
(x,y)对数
具体可看代码
C o d e \mathcal{Code} Code
S
o
l
u
t
i
o
n
2
Solution\ 2
Solution 2
因为这种好实现些,所以就写的这种
/*******************************
Author:Morning_Glory
LANG:C++
Created Time:2019年09月23日 星期一 19时48分07秒
*******************************/
#include <cstdio>
#include <fstream>
#include <cstring>
#define ll long long
#define reset(x) memset(x,0,sizeof(x))
using namespace std;
const int maxn = 3000006;
const int lim = 29;
//{{{cin
struct IO{
template<typename T>
IO & operator>>(T&res){
res=0;
bool flag=false;
char ch;
while((ch=getchar())>'9'||ch<'0') flag|=ch=='-';
while(ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch^'0'),ch=getchar();
if (flag) res=~res+1;
return *this;
}
}cin;
//}}}
int T,n,v,tot;
int ch[maxn][2],s[lim+1][2];
ll sum[maxn],cnt[maxn];
void insert (int rt,int v,int d)
{
if (d<0) return;
int c=(v>>d)&1;
if (!ch[rt][c]) ch[rt][c]=++tot;
rt=ch[rt][c];
++cnt[rt],sum[rt]+=++s[d][c];
insert(rt,v,d-1);
}
ll query (int rt,int v,int d)
{
if (d<0) return 0;
int c=(v>>d)&1,p=ch[rt][c^1];
return cnt[p]*s[d][c^1]-sum[p]+query(ch[rt][c],v,d-1);
}
int main()
{
cin>>T;
while (T--){
cin>>n;
ll ans=tot=0;
reset(sum),reset(s),reset(ch),reset(cnt);
for (int i=1;i<=n;++i){
cin>>v;
insert(0,v,lim);
ans+=query(0,v,lim);
}
printf("%lld\n",ans);
}
return 0;
}
如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧