Codefest 2019 比赛总结

蒟蒻的心路历程

上来看B,结果不会。。。

回来做A,写完之后nantf已经切B了。

回来做B,花了13min磕了出来。

继续做C,自闭。

继续做D,花了10min磕了出来。

继续做E,一开始有点自闭,后来口胡了出来,但是实现略微死人,花了1h磕了出来。

继续自闭。。。。。。。

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\))的正多边形,正\(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.

posted @ 2019-08-26 15:22  mizu164  阅读(339)  评论(2编辑  收藏  举报