Codechef LOCAUG17

Posted liouzhou_101

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codechef LOCAUG17相关的知识,希望对你有一定的参考价值。

做完题目很少有写题解的习惯,强行PO一组吧。

 

比赛链接:https://www.codechef.com/LOCAUG17

 

PRINCESS

给定字符串s,问s是否存在长度大于1的回文子串。

解:分两种情况。设n=|s|。

1. 存在回文子串长度为奇数。则存在2<=i<n,使得s[i-1]==s[i+1]。

2. 存在回文子串长度为偶数。则存在1<=i<n,使得s[i]==s[i+1]。

时间复杂度O(n)。

 

ALATE

给定长度为n的数组a[1..n]。维护两种操作:

1. 给定x,求$\sum_{x|i} a[i]$。

2. 给定x和y,把a[x]改为y。

解:维护ans[x] = $\sum_{x|i} a[i]$。

0. 暴力预处理得到ans[]的初值。

1. 对于操作1,直接输出ans[x]。

2. 对于操作2,枚举所有d|x,更改ans[d]。

时间复杂度$O(n\log n+n \max\limits_{1 \le k \le 100,000} \sigma(k))$,其中$\sigma(k)$表示k的因子个数。

 

ALTSUB

给定长度为n的数组a[1..n]。维护两种操作:

1. 给定x和y,把a[x]改为y。

2. 给定L和R,求a[L], a[L+1], ..., a[R]的所有子序列的交错和的平方之和。

一个序列a[1], a[2], ..., a[n]的交错和定义为$\sum_{i=1}^n (-1)^{i-1} a[i]$。

解:考虑使用线段树。

每个区间维护6个信息:

cnt0 - 这段区间中长度为偶数的子序列个数。

cnt1 - 这段区间中长度为奇数的子序列个数。

sum0 - 这段区间中长度为偶数的子序列的交错和之和。

sum1 - 这段区间中长度为奇数的子序列的交错和之和。

sum20 - 这段区间中长度为偶数的子序列的交错和的平方之和。

sum21 - 这段区间中长度为奇数的子序列的交错和的平方之和。

具体更新信息如下:

void update(node *tree, int k)
{
    tree[k].cnt0 = (tree[k<<1].cnt0*tree[k<<1|1].cnt0+tree[k<<1].cnt1*tree[k<<1|1].cnt1)%MOD;
    tree[k].cnt1 = (tree[k<<1].cnt0*tree[k<<1|1].cnt1+tree[k<<1].cnt1*tree[k<<1|1].cnt0)%MOD;
    tree[k].sum0 = (tree[k<<1|1].cnt0*tree[k<<1].sum0+tree[k<<1].cnt0*tree[k<<1|1].sum0+tree[k<<1|1].cnt1*tree[k<<1].sum1-tree[k<<1].cnt1*tree[k<<1|1].sum1)%MOD;
    tree[k].sum1 = (tree[k<<1|1].cnt0*tree[k<<1].sum1-tree[k<<1].cnt1*tree[k<<1|1].sum0+tree[k<<1|1].cnt1*tree[k<<1].sum0+tree[k<<1].cnt0*tree[k<<1|1].sum1)%MOD;
    tree[k].sum20 =(tree[k<<1|1].cnt0*tree[k<<1].sum20+tree[k<<1].cnt0*tree[k<<1|1].sum20+2*tree[k<<1].sum0*tree[k<<1|1].sum0
                +    tree[k<<1|1].cnt1*tree[k<<1].sum21+tree[k<<1].cnt1*tree[k<<1|1].sum21-2*tree[k<<1].sum1*tree[k<<1|1].sum1)%MOD;
    tree[k].sum21 =(tree[k<<1|1].cnt1*tree[k<<1].sum20+tree[k<<1].cnt0*tree[k<<1|1].sum21+2*tree[k<<1].sum0*tree[k<<1|1].sum1
                +    tree[k<<1|1].cnt0*tree[k<<1].sum21+tree[k<<1].cnt1*tree[k<<1|1].sum20-2*tree[k<<1].sum1*tree[k<<1|1].sum0)%MOD;
}

时间复杂度O(n+mlogn)。

 

GTREE

给定一棵n个节点,并以1为根的树,其每个点x有权值a[x]。

对于每个节点x,问其子树中的所有节点中(不包括节点x本身),有多少个节点y满足 $\gcd (a[x], a[y]) > 1$。

解:先考虑这样一个问题:

【假设给定若干个数字,并且数字x出现c[x]次。问有多少个数字与m的最大公约数大于1。】

由Mobius反演可得

$$\sum_{i=1}^n c_i [\gcd (i, m) = 1] = \sum_{d|m} \mu(d) \sum_{i=1}^{\lfloor n/d \rfloor} c_{id}.$$

我们可以利用一些dfs的技巧,在dfs整棵树的同时,对每个节点x,以及每个d|a[x],O(1)地求得$\sum_{i=1}^{\lfloor n/d \rfloor} c_{id}$。

于是,时间复杂度是$O(n \max\limits_{1 \le k \le 100,000} \sigma(k))$,其中$\sigma(k)$表示k的因子个数。

 

KMAX

给定数组a[1], a[2], ..., a[n],以及k<=n。其中k<=100,n<=100000。

令f(i, j)表示子数组a[i], a[i+1], ..., a[j]的前k大值之和(如果不足k个就全取)。

求$\sum_{i=1}^n \sum_{j=i}^n f(i, j)$。

解:从小到大枚举a[x]的位置x,我们统计位于位置x的a[x]可以对多少个子数组的f(i, j)有贡献。

于是我们只需求得在位置x之前,大于a[x]的最近k个位置;以及在位置x之后,大于a[x]的最近k个位置。(可以利用线段树等求得,也可以利用并查集来做。)

统计所有求和即可。

时间复杂度O(nklogn)。

以上是关于Codechef LOCAUG17的主要内容,如果未能解决你的问题,请参考以下文章

codechef AUG17 T3 Greedy Candidates

codechef AUG17 T2 Chef and Mover

codechef AUG17 T4 Palindromic Game

codechef AUG17 T1 Chef and Rainbow Array

codechef AUG17 T5 Chef And Fibonacci Array

IDE 中的代码正确,但 CodeChef 中出现错误