Codefest 2019 比赛总结

A XORinacci

\(a,b,a\oplus b,a,b,a\oplus b,\ldots\)

B Uniqueless

使用two-pointer, 前缀和优化后判断\(O(n)\),时间复杂度\(O(n^2)\)

D Restore Permutation

从后往前确定,目前求\(p_i\),已知\(\{p_1,p_2,\ldots,p_i\}\)\(s_i\),可以通过线段树上二分得到\(p_i\),之后把\(p_i\)从线段树中删去。时间复杂度\(O(n\log n)\)

E Let them Slide

对于一个数列\(a[1,l]\),设其中的最大值为\(a[p]\),则在\([p,p+w-l]\)这段区间的贡献为\(a[p]\),在\([1,p-1]\)这段区间中\(i\)的贡献为\(\max\limits_{j\in [\max(1,i-w+l),i]}a_j\)\([p+w-l+1,w]\)这段区间中\(i\)的贡献为\(\max\limits_{j\in [i,\min(w,i+w-l)]}a_j\),特别要考虑是否能不经过一个点\(i\),还有\(a[p]<0\)的情况也需要特殊考虑中间这段\([p,p+w-l]\)(其他的贡献为0)。这个取\(\max\)的运算可以使用单调队列计算。

由于\([p,p+w-l]\)这段区间非常大,所以可以打一个全局tag,表示所有数加上多少。

然后加一堆判断并注意正负号就可以过了。

#include<bits/stdc++.h>
#define Rint register int
using namespace std;
typedef long long LL;
const int N = 1000003;
int n, w, l, a[N], p, q[N], front, rear;
LL all, ans[N]; 
int main(){
    scanf("%d%d", &n, &w);
    for(Rint i = 1;i <= n;i ++){
        scanf("%d", &l); p = 1;
        for(Rint j = 1;j <= l;j ++){
            scanf("%d", a + j);
            if(a[j] > a[p]) p = j;
        }
        if(a[p] < 0){
            if(w >= 2 * l) continue;
            int tmp = w - l; front = rear = 0;
            for(Rint i = 1;i <= tmp;i ++){
                while(front < rear && a[q[rear - 1]] <= a[i]) -- rear;
                q[rear ++] = i;
            }
            for(Rint i = tmp + 1;i <= l;i ++){
                while(front < rear && q[front] < i - tmp) ++ front;
                while(front < rear && a[q[rear - 1]] <= a[i]) -- rear;
                q[rear ++] = i;
                ans[i] -= a[q[front]];
            }
            continue;
        }
        all += a[p];
        int tmp = w - l; front = rear = 0;
        for(Rint i = 1;i <= p - 1;i ++){
            while(front < rear && q[front] < i - tmp) ++ front;
            while(front < rear && a[q[rear - 1]] <= a[i]) -- rear;
            q[rear ++] = i;
            if(i <= tmp) ans[i] += min(a[p], a[p] - a[q[front]]);
            else ans[i] += a[p] - a[q[front]];
        }
        front = rear = 0;
        for(Rint i = w;i > p + tmp;i --){
            while(front < rear && q[front] > i) ++ front;
            while(front < rear && a[q[rear - 1]] <= a[i - tmp]) -- rear;
            q[rear ++] = i - tmp;
            if(i > l) ans[i] += min(a[p], a[p] - a[q[front]]);
            else ans[i] += a[p] - a[q[front]];
        }
    }
    for(Rint i = 1;i <= w;i ++)
        printf("%I64d ", all - ans[i]);
}

C Magic Grid

将所有数按照\(x>>4\)分类,填进\(\frac{n}{4}\times \frac{n}{4}\)的矩阵中,一类的\(16\)个数填进一个方格,每个方格是样例1的矩阵。这样在\(8|n\)的时候每行每列为0,否则每行每列为13.

F Bits And Pieces

首先固定\(a_i\),然后从高位到低位试答案,这一位可以填1当且仅当\(a_i\)的这一位为1或者是当前答案\(x\)的超集在\(a_i\)右边至少有两个数。

考虑预处理出\(x\)的超集的最靠右的两个下标。这个可以用FMT做,具体就是对每个\([0,2^{21})\)的数维护一个pair,维护值为\(x\)的最靠右的两个下标。然后把FMT的加法改成合并pair运算(将一个pair的两个数加进另一个pair)就可以了。之后上面的条件就可以轻松判断了。

时间复杂度\(O((n+m)\log m)\)

G Polygons

首先我们知道,肯定要固定一个点,所有的正多边形都要用这个点。

其次,如果填了一个正\(x\)边形,那么\(x\)的所有约数的正多边形也要填入。且相对于\(x\)的所有的约数(不含\(x,1,2\))的正多边形,正\(x\)边形要多用\(\varphi(x)\)个点。所以考虑按照\([1,n]\)的所有\(\varphi\)值排序,然后取最小的\(k\)个,同时我们知道\(d|x\)\(\varphi(d)\le \varphi(x)\),所以满足这个条件。

注意判掉正1边形和正2边形。时间复杂度\(O(n\log n)\)

H Red Blue Tree

此题过 ♂ 难,只会膜倒数2min切掉这题的tourist.

猜你喜欢

转载自www.cnblogs.com/AThousandMoons/p/11412734.html