2019-2020 ICPC, Asia Jakarta Regional Contest


Contest Info


[Practice Link](https://codeforces.com/contest/1252)
Solved A B C D E F G H I J K L
7/12 O - O - O - O O - O O -
  • O 在比賽中通過
  • Ø 賽后通過
  • ! 嘗試了但是失敗了
  • - 沒有嘗試

Solutions


A. Copying Homework

簽到。

C. Even Path

題意:
給出一個\(n \cdot n\)的矩陣,再給出兩個長度為\(n\)的序列\(b, c\),並且有\(a_{i, j} = b_i + c_j\),定義一條'Even Path'為一條經過的格子上面都是偶數的路徑。
現在每次詢問給出\(x_1, y_1, x_2, y_2\),詢問\((x_1, y_1) \rightarrow (x_2, y_2)\)是否存在一條'Even Path'

思路:
發現路徑的擴展每次都是擴展一行或者一列,那么當且僅當\(b[x_1] \cdots b[x_2]\)這一段數的奇偶性相同並且\(c[x_1] \cdots c[x_2]\)這一段數的奇偶性相同即可。

代碼:

view code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, q, a[N], b[N], idA[N], idB[N];

int main() {
	while (scanf("%d%d", &n, &q) != EOF) {
		for (int i = 1; i <= n; ++i) {
			scanf("%d", a + i);
			a[i] %= 2;
		}
		for (int i = 1; i <= n; ++i) {
			scanf("%d", b + i);
			b[i] %= 2;
		}
		idA[1] = 1;
		idB[1] = 1;
		for (int i = 2; i <= n; ++i) {
			if (a[i] == a[i - 1]) {
				idA[i] = idA[i - 1];
			} else {
				idA[i] = idA[i - 1] + 1;
			}
			if (b[i] == b[i - 1]) {
				idB[i] = idB[i - 1];
			} else {
				idB[i] = idB[i - 1] + 1;
			}
		//	cout << idA[i] << " " << idB[i] << endl;
		}
		int x[2], y[2];
		while (q--) {
			scanf("%d%d%d%d", x, y, x + 1, y + 1);
			if (idA[x[0]] == idA[x[1]] && idB[y[0]] == idB[y[1]]) {
				puts("YES");
			} else {
				puts("NO");
			}
		}
	}
	return 0;
}

E. Songwriter

題意:
給出一個序列\(a_i\),要求構造一個序列\(b_i\),滿足\(b_i \in [L, R]\),並且\(b_i\)\(b_{i + 1}\)的大小關系和\(a_i\)\(a_{i + 1}\)相同
並且滿足對於任意\(i \in [1, n - 1]\),都有\(|b_i - b_{i + 1}| \leq K\)
輸出滿足要求的字典序最小的\(b_i\)

思路:
\(l_n = L, r_n = R\),然后往前推出每個\(b_i\)的合法取值范圍。
然后從前往后貪心即可。

代碼:

view code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, L, R, K, a[N], l[N], r[N];

void gao() {
	l[n] = L, r[n] = R;
	for (int i = n - 1; i >= 1; --i) {
		if (a[i] == a[i + 1]) {
			l[i] = l[i + 1];
			r[i] = r[i + 1];
		} else if (a[i] < a[i + 1]) {
			r[i] = r[i + 1] - 1;
			l[i] = max(L, l[i + 1] - K);
		} else if (a[i] > a[i + 1]) {
			l[i] = l[i + 1] + 1;
			r[i] = min(R, r[i + 1] + K);
		}
		if (l[i] > r[i]) {
			puts("-1");
			return;
		}
	}
	int x = l[1];
	for (int i = 1; i <= n; ++i) {
		printf("%d%c", x, " \n"[i == n]);
		if (i < n) {
			if (a[i] < a[i + 1]) {
				x = max(l[i + 1], x + 1);
			} else if (a[i] > a[i + 1]) {
				x = max(x - K, l[i + 1]);
			}
		}	
	}
}

int main() {
	while (scanf("%d%d%d%d", &n, &L, &R, &K) != EOF) {
		for (int i = 1; i <= n; ++i) {
			scanf("%d", a + i);
		}
		gao();
	}
	return 0;
}

G. Performance Review

代碼:

view code
#include <bits/stdc++.h>

using namespace std;

const int N = 2e5 + 10;
const int INF = 0x3f3f3f3f;

int n, m, q;
vector<vector<int> >G;
int a[N], rk[N], remind[N];


struct SEG {
	struct node {
		int Min;
		int lazy;

		node() {}

		node(int _Min, int _lazy) {
			Min = _Min;
			lazy = _lazy;
		}

		void up(int x) {
			Min += x;
			lazy += x;
		}
	}t[N << 2];


	void down(int id) {
		int &lazy = t[id].lazy;
		if (lazy) {
			t[id << 1].up(lazy);
			t[id << 1 | 1].up(lazy);
			lazy = 0;
		}	
	}

	void pushup(int id) {
		t[id].Min = min(t[id << 1].Min, t[id << 1 |1].Min);
	}

	void build(int id, int l, int r) {
		t[id] = {0, 0};
		if (l == r) {
			t[id].Min = remind[l];
			t[id].lazy = 0;
			return ;
		}
		int mid = (l + r) >> 1;
		build(id << 1, l, mid);
		build(id << 1 | 1, mid + 1, r);
		pushup(id);
	}

	void modify(int id, int l, int r, int ql, int qr, int v) {
		if (ql > qr) return ;
		if (l >= ql && r <= qr) {
			t[id].up(v);
			return ;
		}
		int mid = (l + r) >> 1;
		down(id);
		if (ql <= mid) modify(id << 1, l, mid, ql, qr, v);
		if (qr > mid) modify(id << 1 | 1, mid + 1, r, ql, qr, v);
		pushup(id);
	}

	int query(int id, int l, int r, int ql, int qr) {
		if (l >= ql && r <= qr) return t[id].Min;
		int mid = (l + r);
		down(id);
		int res = INF;
		if (ql <= mid) res = min(res, query(id << 1, l, mid, ql, qr));
		if (qr > mid) res = min(res, query(id << 1 | 1, mid + 1, r, ql, qr));
		return res;
	}
}seg;

int main() {
	while (scanf("%d %d %d", &n, &m, &q) != EOF) {
		G.clear();
		G.resize(m + 1);
		rk[1] = 1;
		for (int i = 1; i <= n; ++i) {
			scanf("%d", a + i);
			if (a[i] > a[1]) {
				rk[1]++;
			}
		}
		for (int i = 1, r, b; i <= m; ++i) {
			scanf("%d", &r);
			rk[i + 1] = rk[i];
			for (int j = 1; j <= r; ++j) {
				scanf("%d", &b);
				G[i].push_back(b);
				if (b > a[1]) {
					rk[i + 1]++;
				}
			}
			remind[i] = n - r - rk[i];
		}
		seg.build(1, 1, m);
		for (int _q = 1, x, y, z; _q <= q; ++_q) {
			scanf("%d %d %d", &x, &y, &z);
			int pre = G[x][y - 1], now = z;
			if (pre < a[1] && now > a[1]) {
				seg.modify(1, 1, m, x + 1, m, -1);
			}
			if (pre > a[1] && now < a[1]) {
				seg.modify(1, 1, m, x + 1, m, 1);
			}
			int rank = seg.t[1].Min;
			puts(rank < 0 ? "0" : "1");
			G[x][y - 1] = z;
		}
	}
	return 0;
}

H. Twin Buildings

題意:
給出\(n\)個地基,要造兩個占地面積相同(長寬相同)的房子,問最大占地面積是多少。
可以建在兩個地基上,也可以建在一個地基上

思路:

  • 建在一個地基上:暴力枚舉
  • 建在兩個地基上:容易發現,肯定有其中一個地基的一邊被完整用上了,那么枚舉這一邊,然后在從所有最長邊大於等於這個變成的地基中按另一邊排序選最大和次大來建,這個用堆維護即可

代碼:

view code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 10;
int n, ce; 
struct E {
	ll x, y; int id;
	bool operator < (const E &other) const {
		return x < other.x;
	}
}e[N];

int main() {
	while (scanf("%d", &n) != EOF) {
		ce = 0;
		for (int i = 1, x, y; i <= n; ++i) {
			scanf("%d%d", &x, &y);
			e[++ce] = {x, y, i};
			e[++ce] = {y, x, i};
		}
		sort(e + 1, e + 1 + ce);
		priority_queue <E> pq; 
		ll res = 0;
		for (int i = ce; i >= 1; --i) {
			res = max(res, e[i].x * e[i].y);
			ll now = e[i].x;
			pq.push({e[i].y, e[i].x, e[i].id});
			while (pq.size() > 1) {
				E t1 = pq.top(); pq.pop();
				E t2 = pq.top(); pq.pop();
				if (t1.id == t2.id) {
					pq.push(t1);
				} else {
					pq.push(t1);
					pq.push(t2);
					break;
				}	
			}
			if (pq.size() > 1) {
				E t1 = pq.top(); pq.pop();
				E t2 = pq.top(); pq.pop();
				res = max(res, now * t2.x * 2);
				pq.push(t1);
				pq.push(t2);
			}
		}
		printf("%lld", res / 2);
		puts((res % 2) ? ".5" : ".0");
	}
	return 0;
}

J. Tiling Terrace

題意:
給出一個字符串,里面只包含'.', '#':

  • 如果拼成'.',那么會得到\(G_1\)的分數
  • 如果拼成'..',那么會得到\(G_2\)的分數
  • 如果拼成'.#.',那么會得到\(G_3\)的分數

現在要將該字符串分成若干段,每一段都是上述的某一個,使得分數最大,並且保證字符串中'#'的個數不超過\(50\)
但是分段后,要滿足第一種類型字符串不超過\(K\)

思路:
考慮'..'可以換成兩個'.',所以\(f[i][j]\)表示前\(i\)個字符,有\(j\)個第三種類型字符串的情況下,最多包含多少個第二類型字符串,然后枚舉每種狀態貪心即可。

代碼:

view code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 10;
int n, limit, pre[N], g[3], f[N][60];
char s[N];

ll get(ll x, ll y) {
	if (x >= limit || g[0] * 2 <= g[1]) {
		x = min(x, 1ll * limit);
		return x * g[0] + y * g[1];
	}
	if (limit - x >= y * 2) {
		x += y * 2;
		return x * g[0];
	}
	if ((limit - x) % 2 == 0) {
		int need = limit - x;
		y -= need / 2;
		x += need;	
		return x * g[0] + y * g[1];
	} else {
		int need = limit - x - 1;
		y -= need / 2;
		x += need;
		--y;
		return x * g[0] + y * g[1] + max(g[0], g[1]); 
	}
}

int main() {
	while (scanf("%d%d", &n, &limit) != EOF) {
		memset(f, 0, sizeof f);
		for (int i = 0; i < 3; ++i) scanf("%d", g + i);
		scanf("%s", s + 1);
		memset(f, -0x3f, sizeof f);
		f[0][0] = 0;
		pre[0] = 0;
		for (int i = 1; i <= n; ++i) {
			pre[i] = pre[i - 1] + (s[i] == '.');
			for (int j = 0; j <= 50; ++j) {
				f[i][j] = f[i - 1][j];
			}
			if (i > 1 && s[i] == '.' && s[i - 1] == '.') {
				for (int j = 0; j <= 50; ++j) {
					f[i][j] = max(f[i][j], f[i - 2][j] + 1);
				}
			}
			if (i > 2 && s[i] == '.' && s[i - 1] == '#' && s[i - 2] == '.') {
				for (int j = 0; j <= 50; ++j) {
					f[i][j + 1] = max(f[i][j + 1], f[i - 3][j]);
				}
			}
		}
		ll res = 0;
		for (int i = 1; i <= n; ++i) {
			for (int j = 0; j <= 50 && f[i][j] >= 0; ++j) {
				ll now = 1ll * j * g[2];
				ll x = pre[i] - (j + f[i][j]) * 2;
				ll y = f[i][j];
				now += get(x, y);
				res = max(res, now);
			}
		}
		printf("%lld\n", res);
	}
	return 0;
}

K. Addition Robot

線段樹維護矩陣乘法。

代碼:

view code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, mod = 1e9 + 7;
int n, q; char s[N];
struct Matrix {
	int a[2][2];
	void init() { a[0][0] = a[1][1] = 1; a[0][1] = a[1][0] = 0; }
	int* operator[] (int x) { return a[x]; } 
	Matrix operator * (Matrix b) {
		Matrix res;
		res[0][0] = (1ll * a[0][0] * b[0][0] % mod + 1ll * a[0][1] * b[1][0] % mod) % mod;
		res[0][1] = (1ll * a[0][0] * b[0][1] % mod + 1ll * a[0][1] * b[1][1] % mod) % mod;
		res[1][0] = (1ll * a[1][0] * b[0][0] % mod + 1ll * a[1][1] * b[1][0] % mod) % mod;
		res[1][1] = (1ll * a[1][0] * b[0][1] % mod + 1ll * a[1][1] * b[1][1] % mod) % mod;
		return res;
	}
}A, B, res;

struct SEG {
	struct node {
		Matrix a[2];
		int lazy;
		void init() {
			a[0].init(); a[1].init();
			lazy = 0;
		}
		void up() {
			swap(a[0], a[1]);
			lazy ^= 1;
		}
	}t[N << 2];
	void pushup(int id) {
		t[id].a[0] = t[id << 1 | 1].a[0] * t[id << 1].a[0];
		t[id].a[1] = t[id << 1 | 1].a[1] * t[id << 1].a[1];
	}
	void down(int id) {
		int &lazy = t[id].lazy;
		if (lazy) {
			t[id << 1].up();
			t[id << 1 | 1].up();
			lazy = 0;
		}
	}
	void build(int id, int l, int r) {
		if (l == r) {
			t[id].a[0] = A;
			t[id].a[1] = B;
			if (s[l] == 'B') {
				swap(t[id].a[0], t[id].a[1]);
			}
			return;
		}
		int mid = (l + r) >> 1;
		build(id << 1, l, mid);
		build(id << 1 | 1, mid + 1, r);
		pushup(id);
	}
	void modify(int id, int l, int r, int ql, int qr) {
		if (l >= ql && r <= qr) {
			t[id].up();
			return;
		}
		int mid = (l + r) >> 1;
		down(id);
		if (ql <= mid) modify(id << 1, l, mid, ql, qr);
		if (qr > mid) modify(id << 1 | 1, mid + 1, r, ql, qr);
		pushup(id);
	}
	Matrix query(int id, int l, int r, int ql, int qr) {
		if (l >= ql && r <= qr) return t[id].a[0];
		int mid = (l + r) >> 1;
		down(id);
		Matrix res; res.init();
		if (qr > mid) res = res * query(id << 1 | 1, mid + 1, r, ql, qr);
		if (ql <= mid) res = res * query(id << 1, l, mid, ql, qr);
		return res;
	}
}seg;


int main() {
	A = {1, 1, 0, 1};
	B = {1, 0, 1, 1};
	while (scanf("%d%d", &n, &q) != EOF) {
		scanf("%s", s + 1);
		seg.build(1, 1, n);
		int op, l, r, a, b;	
		for (int i = 1; i <= q; ++i) {
			scanf("%d%d%d", &op, &l, &r);
			if (op == 1) {
				seg.modify(1, 1, n, l, r);
			} else {
				scanf("%d%d", &a, &b);
				res = {a, 0, b, 0};
				res = seg.query(1, 1, n, l, r) * res;
				printf("%d %d\n", res[0][0], res[1][0]);						
			}
		}
	}	
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM