当前位置: 首页 > 工具软件 > Eurasia > 使用案例 >

Northern Eurasia Finals Online 2020 队内训练

司空凌
2023-12-01

A. Almost Balanced Tree

  • 考虑一种做法,先分配权值为2的点,每次都将权值为2的点数二等分,若是偶数就往下分,否则自身先占用一个再往下分
  • 权值为2的点分配完后,对整一棵树的空位分配权值为1的点
  • 若不够分,则无解
  • 若多出来了,同样将1的个数二分往下
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e6 + 10;
const int INF = 0x3f3f3f3f;
ll gcd(ll x, ll y) {
	if (y == 0) return x;
	return gcd(y, x % y);
}
int n, m;
int num[N] = { 0 }, id[N] = { 0 }, rid[N];
bool vis[N] = { false };
void dfs(int x, int cnt) {
	vis[x] = true;
	if (cnt & 1) num[x] = 2, --cnt;
	if (cnt) {
		dfs(x << 1, cnt >> 1);
		dfs(x << 1 | 1, cnt >> 1);
	}
}
void dfs1(int x, int& tot) {
	if (num[x] == 0) num[x] = 1, ++tot;
	if (vis[x << 1]) dfs1(x << 1, tot);
	if (vis[x << 1 | 1]) dfs1(x << 1 | 1, tot);
}
void dfs2(int x, int tot) {
	vis[x] = true;
	if (!num[x] && tot) num[x] = 1, --tot;
	//	printf("%d %d\n", x, num[x]);
	if (tot > 0) {
		int tmp = tot >> 1;
		dfs2(x << 1, tmp);
		dfs2(x << 1 | 1, tot - tmp);
	}
}
void dfs3(int x, int& tot) {
	if (num[x]) {
		id[x] = ++tot;
		rid[tot] = x;
	}
	if (vis[x << 1]) dfs3(x << 1, tot);
	if (vis[x << 1 | 1]) dfs3(x << 1 | 1, tot);
}
int main() {
	int x, y;
	scanf("%d %d", &x, &y);
	dfs(1, y);
	int tot = 0;
	dfs1(1, tot);
	if (tot > x) puts("-1");
	else {
		x -= tot;
		dfs2(1, x);
		int tmp = 0;
		dfs3(1, tmp);
		for (int i = 1; i <= tmp; ++i) {

			int u = rid[i];
			printf("%d %d %d\n", num[u], id[u << 1], id[u << 1 | 1]);
		}
	}
	return 0;
}


C. Color the Tree

  • 对于子结点来回反复刷,乱搞
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
template<typename T>
inline void rd(T& x)
{
	int tmp = 1; char c = getchar(); x = 0;
	while (c > '9' || c < '0') { if (c == '-')tmp = -1; c = getchar(); }
	while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	x *= tmp;
}
const int N = 3e5 + 10;
const int M = 1e7 + 10;
const int mod = 1e9 + 7, inf = 0x3f3f3f3f;
ll gcd(ll x, ll y) { if (y == 0) return x; return gcd(y, x % y);}
int head[N], cntE = 0;
struct edge {
	int next, to, w;
}e[M];
void add(int u, int v, int w = 0) {
	e[cntE].to = v;
	e[cntE].next = head[u];
	e[cntE].w = w;
	head[u] = cntE++;
}
int n, m;
vector<int> dfs(int x) {
	vector<int>ans;
	for (int i = head[x]; ~i; i = e[i].next) {
		int u = e[i].to;
		vector<int>tmp = ans, now = dfs(u);
		int op = 1;
		for (auto v : now) {
			op ^= 1;
			tmp.push_back(v);
			if (op) tmp.insert(tmp.end(), ans.begin(), ans.end());
			else tmp.insert(tmp.end(), ans.rbegin(), ans.rend());
		}
		ans = tmp;
	}
	ans.insert(ans.begin(), x);
	return ans;
}
int main() {
#ifdef _DEBUG
	FILE* _INPUT = freopen("input.txt", "r", stdin);
	//	FILE* _OUTPUT = freopen("output.txt", "w", stdout);
#endif
	rd(n);
	memset(head, -1, sizeof(int) * (n + 10)); cntE = 0;
	for (int i = 2; i <= n; ++i) {
		int x; rd(x);
		add(x, i);
	}
	vector<int>ans = dfs(1);
	printf("%d\n", ans.size() - 1);
	for (int i = 1; i < ans.size(); ++i) {
		printf("%d ", ans[i]);
	}
	puts("");
	return 0;
}


E. Easy Measurements

  • 题目要求
    a b + c d = b d \frac{a}{b}+\frac{c}{d}=\frac{b}{d} ba+dc=db
  • 化简得 a = b ∗ ( b − c ) d a=\frac{b*(b-c)}{d} a=db(bc)
  • 由于 a > 0 a>0 a>0 ,有 0 < c < b 0<c<b 0<c<b
  • 所以就是求有多少个 c c c 满足算出来的 a a a 是整数
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e2 + 10;
const int INF = 0x3f3f3f3f;
ll gcd(ll x, ll y) {
	if (y == 0) return x;
	return gcd(y, x % y);
}
int main() {
	int T = 1;
	scanf("%d", &T);
	while (T--) {
		ll b, d;scanf("%lld %lld", &b, &d);
		if (b % d == 0) {
			printf("%d\n", b - 1);
			continue;
		}
		ll tmp = gcd(b, d);
		d /= tmp;
		ll ans = b / d;
		if (b % d == 0) --ans;
		printf("%lld\n", ans);
	}
}


K. Kate’s 2021 Celebration

  • 签到题
  • 题目给出 n n n个气球包,每个包中都含有标记不同数字的气球和相应的价格。
  • 要找出包含两个 2 2 2一个 1 1 1一个 0 0 0的气球包,并且其价值是最便宜的。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e2 + 10;
const int INF = 0x3f3f3f3f;
int main() {
	int n;
	
	scanf("%d", &n);
	int minn = INF, ans = -1;
	for (int i = 1; i <= n; ++i) {
		int x;
		char s[N];
		scanf("%d %s", &x, s);
		int len = strlen(s);
		int sum0 = 0, sum2 = 0, sum1 = 0;
		for (int j = 0; j < len; ++j) {
			if (s[j] == '0')
				++sum0;
			else if (s[j] == '1')
				++sum1;
			else if (s[j] == '2')
				++sum2;
		}
		if (sum0 >= 1 && sum1 >= 1 && sum2 >= 2) {
			if (x < minn) {
				minn = x;
				ans = i;
			}
		}
	}
	if (ans == -1)
		puts("0");
	else
		printf("%d\n", ans);
	
}

L.Lookup Performance

  • 题意就是求题目所给的函数执行了多少次
  • 现在需要对题目所给的查询区间的 L , R L,R L,R 都找到一个关键的节点,满足这个节点往左下和右下走了之后就会停止这个函数
  • 可以得出,总会存在一个点,往两个儿子走了之后就会暂停这个函数
  • 至于怎么求这个关键的点,根据这个函数要求,比如求 L L L 这个的关键点,需要求出一个点 u u u 满足 w u < L w_u<L wu<L 并且求出一个点 v v v 满足 w v ≥ L w_v\ge L wvL ,而这个关键点就是 l c a ( u , v ) lca(u,v) lca(u,v)
  • 对于 R R R 同样的原理,求出一个点 u u u 满足 w u ≤ R w_u\le R wuR 并且求出一个点 v v v 满足 w v > R w_v> R wv>R ,而这个关键点就是 l c a ( u , v ) lca(u,v) lca(u,v)
  • 先说明一个结论,对于到 L , R L,R L,R 两个关键点的路径中,都会将函数向两个儿子结点执行一次,所以对于此路径中的每一个结点,函数都在这个结点上算上两次。
  • 所以每次查询的从根到关键点的路径长度是 h ( u ) + h ( v ) − h ( l c a ( u , v ) ) h(u)+h(v)-h(lca(u,v)) h(u)+h(v)h(lca(u,v)), u , v u,v u,v L , R L,R L,R 对应的关键点 ,所以每个结点向下执行两次为 路径长度*2,最后再算上一开始的根结点的那份 1,答案便是 ( h ( u ) + h ( v ) − h ( l c a ( u , v ) ) ) ∗ 2 + 1 (h(u)+h(v)-h(lca(u,v)))*2+1 (h(u)+h(v)h(lca(u,v)))2+1
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
template<typename T>
inline void rd(T& x)
{
	int tmp = 1; char c = getchar(); x = 0;
	while (c > '9' || c < '0') { if (c == '-')tmp = -1; c = getchar(); }
	while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	x *= tmp;
}
const int N = 3e5 + 10;
const int M = 1e7 + 10;
const int mod = 1e9 + 7, inf = 0x3f3f3f3f;
ll gcd(ll x, ll y) { if (y == 0) return x; return gcd(y, x % y);}
int head[N], cntE = 0;
struct edge {
	int next, to, w;
}e[M];
void add(int u, int v, int w = 0) {
	e[cntE].to = v;
	e[cntE].next = head[u];
	e[cntE].w = w;
	head[u] = cntE++;
}
int n, m;
struct node {
	int w, id;
	bool friend operator<(const node& a, const node& b) {
		return a.w < b.w;
	}
	node(int w = 0, int id = 0) :w(w), id(id) {}
}a[N];
int fa[N][25] = { 0 }, h[N], lg[N];
void dfs(int x, int fx, int dep) {
	fa[x][0] = fx;
	h[x] = dep;
	for (int i = head[x]; ~i; i = e[i].next) {
		int v = e[i].to;
		dfs(v, x, dep + 1);
	}
}
void init() {
	dfs(1, 0, 1);
	for (int j = 1; j <= 20; ++j) {
		for (int i = 1; i <= n; ++i) {
			fa[i][j] = fa[fa[i][j - 1]][j - 1];
		}
	}
	lg[0] = 0;
	for (int i = 1; i <= N - 10; ++i) {
		lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
	}
}
int lca(int u, int v) {
	if (h[u] < h[v]) swap(u, v);
	for (int i = 0, tmp = h[u] - h[v]; i <= 19; ++i) {
		if ((1 << i) & tmp) u = fa[u][i];
	}
	if (u == v) return u;
	for (int i = lg[h[u]] - 1; i >= 0; --i) {
		if (fa[u][i] != fa[v][i]) {
			u = fa[u][i];
			v = fa[v][i];
		}
	}
	return fa[u][0];
}
int main() {
#ifdef _DEBUG
	FILE* _INPUT = freopen("input.txt", "r", stdin);
	//	FILE* _OUTPUT = freopen("output.txt", "w", stdout);
#endif
	rd(n);
	memset(head, -1, sizeof(int) * (n + 10)); cntE = 0;
	for (int i = 1; i <= n; ++i) {
		int x, y; rd(x), rd(y), rd(a[i].w);
		a[i].id = i;
		if (x) add(i, x);
		if (y) add(i, y);
	}
	init();
	sort(a + 1, a + 1 + n);
	rd(m);
	while (m--) {
		int l, r; rd(l), rd(r);
		if (r<a[1].w || l>a[n].w) {
			puts("1");
			continue;
		}
		int tl, tr;
		if (l <= a[1].w) tl = 0;
		else {
			int tmp = lower_bound(a + 1, a + 1 + n, node(l, 0)) - a;
			tl = lca(a[tmp - 1].id, a[tmp].id);
		}
		if (r >= a[n].w) tr = 0;
		else {
			int tmp = upper_bound(a + 1, a + 1 + n, node(r, 0)) - a;
			tr = lca(a[tmp - 1].id, a[tmp].id);
		}
		int fx = lca(tl, tr);
		int ans = (h[tl] + h[tr] - h[fx]) * 2 + 1;
		printf("%d\n", ans);
	}
	return 0;
}


M. Miser

签到题

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int N = 1e6 + 10;
vector<int>vec[N];
int num[N] = { 0 };
int main() {
	int n;scanf("%d", &n);
	for (int i = 1;i <= n;++i) {
		int k;scanf("%d", &k);
		while (k--) {
			int x;scanf("%d", &x);
			vec[i].push_back(x);
		}
	}
	int ans = 0;
	int maxn = 0;
	for (int i = n;i > 0;--i) {
		maxn = 0;
		for (auto v : vec[i]) {
			maxn = max(maxn, num[v]);
		}
		++maxn;
		for (auto v : vec[i]) {
			num[v] = maxn;
		}
	}
	printf("%d\n", maxn);
}

 类似资料: