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)
