1.
今天看了看昨天晚上没写完的一道题,一道线段树的题,结果理解错题意了。
原题:CodeForces 1000F
我的题面:求数列
a
[
]
a[]
a[]的
[
L
,
R
]
[L,R]
[L,R]区间内有多个数字只出现了一次。
原题意:写出任意一个在数列
a
[
]
a[]
a[]的
[
L
,
R
]
[L,R]
[L,R]区间内只出现过一次的数,没有则输出0。
补:也可以进行区间出现过的不同数的求和·。
不过做法可能差不多,这里简单谈一谈我所学到的做法:
若记
p
r
e
[
x
]
pre[x]
pre[x]为上一次出现
a
[
x
]
a[x]
a[x]的位置,则如果
p
r
e
[
x
]
<
L
pre[x]<L
pre[x]<L,则
a
[
x
]
a[x]
a[x]满足条件。但是这个对于出现过多个数字的数
y
y
y,它的最靠近
L
L
L位置的那个数字的
p
r
e
pre
pre是满足条件的,这就有点难处理。
然后我们观察到,我们只需要保证某个数字最后出现的位置到倒数第二次出现的位置就行了,因为更往前面的该数字一定不满足条件,所以我们考虑如果离线问题。当前的位置的数字
a
[
i
]
a[i]
a[i],如果
p
r
e
[
a
[
i
]
]
pre[a[i]]
pre[a[i]]已经存在,则将
p
r
e
[
a
[
i
]
]
pre[a[i]]
pre[a[i]]的
p
r
e
pre
pre改为
i
n
f
inf
inf。这样如果在
(
p
r
e
[
a
[
i
]
]
,
i
]
(pre[a[i]],i]
(pre[a[i]],i]之间,就可以正常的保证,更之前的也可以保证。用树状数组或线段树来维护
[
1
,
L
)
[1,L)
[1,L)内有多少个值就可以了。
补:将次数改为权值就可以了,主要是
p
r
e
pre
pre处理的思想。
2
还有一个一道昨天打CF的题
CodeForces edu 80D:
有
n
n
n个序列
(
n
<
=
100000
)
(n<=100000)
(n<=100000),序列长度均为
m
m
m
(
m
<
=
8
)
(m<=8)
(m<=8),选出两个序列
a
[
i
]
[
]
,
a
[
j
]
[
]
a[i][],a[j][]
a[i][],a[j][]出来,令
b
[
k
]
=
m
a
x
(
a
[
i
]
[
k
]
,
a
[
j
]
[
k
]
)
b[k]=max(a[i][k],a[j][k])
b[k]=max(a[i][k],a[j][k]),是
m
i
n
k
b
[
k
]
min_{k}b[k]
minkb[k]最大。
最小值最大,二分答案。
附上二分代码:
while(l<r){
int mid=(l+r+1)>>1;
if(check(mid)) l=mid;
else r=mid-1;
}
这里的
c
h
e
c
k
(
x
)
check(x)
check(x)函数,可以用二进制来实现。
让所有的
a
[
i
]
[
k
]
>
=
x
a[i][k]>=x
a[i][k]>=x的二进制位为
1
1
1,不满足的为
0
0
0。对于每个序列,都可以得到一个数字,再用个数组来记录哪些集合已经有序列了。对每一个,枚举一下子集,判断是否有补集已经有序列了。如果没有,将该子集的位置标记为
i
i
i序列;如果有,就已经得到答案了。
一般枚举子集的写法:
for(int x=s;x;x=(x-1)&s) y=s^x;
枚举子集要注意一下
0
0
0的情况。
这里要把
x
=
0
x=0
x=0的情况也加进去。
此时的
y
y
y就是补集,
s
s
s是全集。
3
今天主要学习了分块和莫队。
这两个算法以前都用过,但是都不是很熟练,今天好好回顾了一下。
写分块时,在转移到其他块的时候,写复杂了。可以直接在原序列的基础上算出到达的点,在通过点来计算在哪一个块里面,而不是通过块来算。
莫队算法(不修改)主要在于能否在
O
(
1
)
O(1)
O(1)的时间内,由
[
L
,
R
]
[L,R]
[L,R]转移到
[
L
−
1
,
R
]
,
[
L
,
R
−
1
]
,
[
L
+
1
,
R
]
,
[
L
,
R
+
1
]
[L-1,R],[L,R-1],[L+1,R],[L,R+1]
[L−1,R],[L,R−1],[L+1,R],[L,R+1]。
通过排序来保证算法复杂度。
对
l
l
l进行分块,以
l
l
l所在块为第一关键字,
r
r
r为第二关键字,排序。
基础排序:
bool cmp(Mo x,Mo y){
return x.block==y.block?x.r<y.r:x.block<y.block;
}
优化:
bool cmp(Mo x,Mo y){
return x.block==y.block?(x.block&1?x.r<y.r:x.r>y.r):x.block<y.block;
}
奇偶的 r r r排序方向相反,奇数 r r r增,偶数 r r r减,在理论上能优化一半的复杂度。
4
最后写了一道NCPC2017的G题(Gym 101572G)。
一个有两个关键字
(
x
,
y
)
(x,y)
(x,y)的比较,支持修改。
这里我对
x
x
x都乘以一个
B
a
s
e
Base
Base,使得无论
y
y
y多大,都无法直接影响
x
x
x对大小的影响。这样就可以将其转化为一个关键字了。用树状数组离散化一下就可以了统计了。