2019/11/1 爆零 总结
T1:
大意:给定一个数列
C
n
Cn
Cn,给出
Q
Q
Q个询问m,类型1比较
g
c
d
(
c
i
)
(
1
<
=
i
<
=
n
)
gcd(ci)(1<=i<=n)
gcd(ci)(1<=i<=n)与
m
m
m的大小,类型2判断是否
m
i
n
(
c
i
)
>
m
∗
m
min(ci)>m*m
min(ci)>m∗m
唯一的坑点就是读进来的数可能爆
l
o
n
g
l
o
n
g
long~long
long long,我因为
r
e
a
d
read
read函数中返回答案的
d
a
t
a
data
data变量没有开
L
L
LL
LL挂成
80
p
t
s
80pts
80pts
T2:
大意:
T
T
T次测试,给定一个字符串
S
S
S(1开始标号),每次测试给出
Q
Q
Q组询问,询问
L
L
L到
R
R
R的字串以出现次数为下标的桶与
S
S
S的子串相同的个数
正解是根据当前串与给定串的桶中元素差的绝对值是否为
0
0
0来判断,而这道题可以对70pts的算法进行剪枝而AC
大概有两类思路:
1.维护一个队列,里面只保存当前串对应的桶之中有值的元素的下标,然后只比较这些有值的地方,这样每次询问的复杂度是
O
(
26
∗
n
)
O(26*n)
O(26∗n)的
2.(mine)每次当前串平移只会涉及两个位置上的元素变化,如果前一次的串对答案有贡献,可以
O
(
1
)
O(1)
O(1)判断当前串是否对答案有贡献——比较桶中发生变化的元素即可,而对于前一次无贡献的情况,只有当桶中变化的元素与给定串匹配时我们才去暴力
O
(
n
)
O(n)
O(n)判断,这样每次询问的复杂度是
O
(
n
)
O(n)
O(n)到
O
(
n
2
)
O(n^2)
O(n2)不等的
实测两种剪枝方法效率都差不多,不过与正解差距确实很大
然后我因为一个地方的
j
j
j写成
i
i
i,从
100
p
t
s
100pts
100pts变成了
10
p
t
s
10pts
10pts
T3:
给定序列
a
n
an
an,定义
f
i
=
∑
a
j
(
j
在
i
的
子
树
之
中
)
fi=\sum aj(j在i的子树之中)
fi=∑aj(j在i的子树之中),定义
g
i
gi
gi为
i
i
i可以到达的节点的
f
f
f值的
o
r
or
or和,”
i
i
i可以到达
j
j
j“是指
i
i
i到
j
j
j的简单路径上的
m
a
x
(
f
)
>
f
i
>
m
i
n
(
f
)
max(f)>fi>min(f)
max(f)>fi>min(f),则称”
i
i
i可以到达
j
j
j“,求每个点的
g
g
g值
考场上只打了
40
p
t
s
40pts
40pts的
O
(
n
2
)
O(n^2)
O(n2)做法,正解非常绕,是基于位运算的树形
D
P
DP
DP,不过这道题也可以用
d
f
s
dfs
dfs序+线段树——只需要利用一个我看出来却没有用起来的性质
这个性质就是,整棵树从下往上走的过程中,
f
f
f值是逐渐递增的
因此,对于一个节点
i
i
i,能对其产生贡献的位置一定在其子树外面,并且
f
f
f值比它小的地方
为什么?
因为要满足条件,
i
i
i显然得先向上再向下到达
j
j
j,且
f
j
<
f
i
fj<fi
fj<fi,
j
j
j才能对之产生贡献(此时的
m
a
x
(
f
)
max(f)
max(f)为
f
f
f
l
c
a
lca
lca)
所以对
i
i
i产生贡献的
j
j
j,一定在
i
i
i的子树外且
f
j
<
f
i
fj<fi
fj<fi——就转化成为了一个偏序问题
于是按
f
f
f值排序,就变成了单点修改,区间查值,复杂度
O
(
N
∗
l
o
g
N
)
O(N*logN)
O(N∗logN)