ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces Global Round 21

2022-06-26 11:00:37  阅读:138  来源: 互联网

标签:prime 21 int Global pos Codeforces 250005 premx mod


A

只需要让最大值最大,\(\and\) 过后 \(z\) 不会变大,所以最优策略一定是 \(z\) 或上 \(a\) 中的某个数。

B

判掉答案是 \(0\) 和 \(1\) 的情况,剩下的情况序列中一定有 \(0\),只需要全局取一遍 mex,这样所有数都变成了非 \(0\) 数,然后再全局取一遍 mex 即可,所以答案是 \(2\)。

C

把 \(a\) 和 \(b\) 都按 \(m\) 拆到不能再拆后直接判相等即可。

D

solution 1:

官方题解做法,稍微要点脑子。

显然从 \(1\) 到 \(n\) 不管怎么走一定会路过 \([1,n]\) 最大值所在位置 \(p\)(即 \(a_p=n\))。于是只需计算 \(1\) 走到 \(p\) 与 \(p\) 走到 \(n\) 的最短路。

\(1\) 走到 \(p\) 需要路过 \([1,p]\) 最小值所在位置 \(p^{\prime}\),而 \(p^{\prime}\) 可以一步跳到 \(p\),只需计算 \(1\) 走到 \(p^{\prime}\) 的最短路。

\(1\) 走到 \(p^{\prime}\) 又需要路过 \([1,p^{\prime}]\) 最大值所在位置 \(p^{\prime\prime}\),只需计算 \(1\) 走到 \(p^{\prime\prime}\) 的最短路。

\(p\) 走到 \(n\) 是同理的。

于是只需维护前缀后缀最大最小值所在位置即可。非常优美。

#include <cstdio>

int a[250005], premx[250005], premn[250005], sufmx[250005], sufmn[250005];

int main() {
	int _;
	scanf("%d", &_);
	while (_ --) {
		int n, ans = 0, pos, d;
		scanf("%d", &n);
		for (int i = 1; i <= n; ++ i) scanf("%d", a + i);
		premx[1] = premn[1] = 1, sufmx[n] = sufmn[n] = n;
		for (int i = 2; i <= n; ++ i) {
			if (a[i] > a[premx[i - 1]]) premx[i] = i;
			else premx[i] = premx[i - 1];
			if (a[i] < a[premn[i - 1]]) premn[i] = i;
			else premn[i] = premn[i - 1];
		}
		for (int i = n - 1; i; -- i) {
			if (a[i] > a[sufmx[i + 1]]) sufmx[i] = i;
			else sufmx[i] = sufmx[i + 1];
			if (a[i] < a[sufmn[i + 1]]) sufmn[i] = i;
			else sufmn[i] = sufmn[i + 1];
		}
		d = 0, pos = premx[n];
		while (pos != 1) pos = (d ? premx[pos] : premn[pos]), d ^= 1, ++ ans;
		d = 0, pos = premx[n];
		while (pos != n) pos = (d ? sufmx[pos] : sufmn[pos]), d ^= 1, ++ ans;
		printf("%d\n", ans);
	}
	return 0;
}

solution 2:

赛时的无脑做法,B题-3调了半天才发现答案不超过 \(2\),导致后面很慌,所以看完题想到这个无脑做法直接开始写了。

首先显然每次贪心地跳到最右边能跳的位置是最优的(废话)。

这个跳的过程搞个单调栈求出每个数右边第一个比它大/小的数的位置,加上st表就能跳了。

\(O(n\log n)\),非常粗暴而又丑陋。由于太慌连续两次数组开小白送两发罚时(外加10min)。

#include <cstdio>
#include <cstring>

inline int min(const int x, const int y) {return x < y ? x : y;}

int a[250005], st1[250005][20], st2[250005][20], Log[250005], rmn[250005], rmx[250005], stk[250005], top;
inline int querymin(int l, int r) {
	int k = Log[r - l + 1];
	return a[st1[l][k]] < a[st1[r - (1 << k) + 1][k]] ? st1[l][k] : st1[r - (1 << k) + 1][k];
}
inline int querymax(int l, int r) {
	int k = Log[r - l + 1];
	return a[st2[l][k]] > a[st2[r - (1 << k) + 1][k]] ? st2[l][k] : st2[r - (1 << k) + 1][k];
}

int main() {
	int _;
	scanf("%d", &_);
	while (_ --) {
		int n, ans = 0;
		scanf("%d", &n);
		for (int i = 1; i <= n; ++ i) scanf("%d", a + i), st1[i][0] = st2[i][0] = i;
		for (int i = 2; i <= n; ++ i) Log[i] = Log[i >> 1] + 1;
		for (int j = 1; j < 20; ++ j)
		for (int i = 1; i + (1 << j) - 1 <= n; ++ i) {
			if (a[st1[i][j - 1]] < a[st1[i + (1 << j - 1)][j - 1]]) st1[i][j] = st1[i][j - 1];
			else st1[i][j] = st1[i + (1 << j - 1)][j - 1];
			if (a[st2[i][j - 1]] > a[st2[i + (1 << j - 1)][j - 1]]) st2[i][j] = st2[i][j - 1];
			else st2[i][j] = st2[i + (1 << j - 1)][j - 1];
		}
		top = 0;
		for (int i = 1; i <= n; ++ i) {
			while (top && a[stk[top]] > a[i]) rmn[stk[top --]] = i;
			stk[++ top] = i;
		}
		while (top) rmn[stk[top --]] = n + 1;
		for (int i = 1; i <= n; ++ i) {
			while (top && a[stk[top]] < a[i]) rmx[stk[top --]] = i;
			stk[++ top] = i;
		}
		while (top) rmx[stk[top --]] = n + 1;
		for (int i = 1; i < n;)
			if (a[i] < a[i + 1]) i = querymax(i, rmn[i] - 1), ++ ans;
			else i = querymin(i, rmx[i] - 1), ++ ans;
		printf("%d\n", ans);
	}
	return 0;
}

E

草稿本上自己画一画就能发现这玩意儿就是个杨辉三角也就是组合数。

由于保证了 \(a_i\) 单调不增,所以答案就是 \(\sum\limits^n_{i=0}\tbinom{i+1+a_i-1}{a_i-1}\)。

比做D的时候还要慌,导致没取模白给一发,预处理数组没乘二白给一发,罚时上天,-7,被一堆4题人吊打。

#include <cstdio>

const int mod = 1e9 + 7;
int a[400005], fact[400005], inv[400005];
inline int qpow(int a, int b) {
	int ret = 1;
	while (b) {
		if (b & 1) ret = 1ll * ret * a % mod;
		a = 1ll * a * a % mod, b >>= 1;
	}
	return ret;
}
inline int C(int n, int m) {
	return 1ll * fact[n] * qpow(fact[m], mod - 2) % mod * qpow(fact[n - m], mod - 2) % mod;
}

int main() {
	fact[0] = 1;
	for (int i = 1; i <= 400004; ++ i) fact[i] = 1ll * fact[i - 1] * i % mod;
	int n, ans = 0;
	scanf("%d", &n);
	for (int i = 0, x; i <= n; ++ i) scanf("%d", &x), ans = (ans + C(i + 1 + x - 1, x - 1)) % mod;
	printf("%d", ans);
	return 0;
}

标签:prime,21,int,Global,pos,Codeforces,250005,premx,mod
来源: https://www.cnblogs.com/stinger/p/16413114.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有