1. 程式人生 > >Codechef LOCAUG17

Codechef LOCAUG17

cnblogs 更改 習慣 長度 子數組 給定 sigma mod pre

做完題目很少有寫題解的習慣,強行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