Codefest 2019 比赛总结

蒟蒻的心路历程

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

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

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

继续做C,自闭。

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

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

继续自闭。。。。。。。

A XORinacci

(a,b,aoplus b,a,b,aoplus 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(nlog n))

E Let them Slide

对于一个数列(a[1,l]),设其中的最大值为(a[p]),则在([p,p+w-l])这段区间的贡献为(a[p]),在([1,p-1])这段区间中(i)的贡献为(maxlimits_{jin [max(1,i-w+l),i]}a_j)([p+w-l+1,w])这段区间中(i)的贡献为(maxlimits_{jin [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} imes 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(nlog n))

H Red Blue Tree

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

原文地址:https://www.cnblogs.com/AThousandMoons/p/11412734.html