Codeforces Global Round 4


Contest Info


[Practice Link](https://codeforc.es/contest/1178)
Solved A B C D E F1 F2 G H
6/9 O O O O O Ø - - -
  • O 在比賽中通過
  • Ø 賽后通過
  • ! 嘗試了但是失敗了
  • - 沒有嘗試

Solutions


A. Prime Minister

簽到題。

#include <bits/stdc++.h>
using namespace std;
 
#define N 110
int n, a[N], b[N];
 
int main() {
	while (scanf("%d", &n) != EOF) {
		memset(b, 0, sizeof b);
		int sum = 0, other = 0;
		for (int i = 1; i <= n; ++i) scanf("%d", a + i), sum += a[i];
		b[1] = 1;
		other = a[1];
		for (int i = 2; i <= n; ++i) {
			if (a[1] >= a[i] * 2) {
				other += a[i];
				b[i] = 1;
			}
		}
		if (other > sum / 2) {
			int sze = 0;
			vector <int> vec;
			for (int i = 1; i <= n; ++i) {
				if (b[i]) {
					++sze;
					vec.push_back(i);
				}
			}
			printf("%d\n", sze);
			for (int i = 0; i < sze; ++i) printf("%d%c", vec[i], " \n"[i == sze - 1]);
		} else {
			puts("0");
		}
	}
	return 0;
}

B. WOW Factor

題意:
將連續的兩個\(v\)可以看成一個\(w\),詢問給出的字符串中只包含字符\(v\)\(o\),詢問有多少個子序列組成\(wow\)

思路:
先處理出每個\(o\)左邊有多少個\(w\)以及右邊有多少個\(w\),然后計算貢獻即可。

代碼:

#include <bits/stdc++.h>
using namespace std;
 
#define ll long long
#define N 1000010
int n;
ll l[N], r[N];
char s[N];
 
int main() {
	while (scanf("%s", s + 1) != EOF) {
		n = strlen(s + 1);
		l[0] = 0;
		for (int i = 1; i <= n; ++i) {
			l[i] = l[i - 1];
			if (i > 1 && s[i] == 'v' && s[i - 1] == 'v') {
				++l[i];
			}
		}
		r[n + 1] = 0;
		for (int i = n; i >= 1; --i) {
			r[i] = r[i + 1];
			if (i < n && s[i] == 'v' && s[i + 1] == 'v') {
				++r[i];
			}
		}
		ll res = 0;
		for (int i = 1; i <= n; ++i) {
			if (s[i] == 'o') {
				res += 1ll * l[i - 1] * r[i + 1];
			}
		}
		printf("%lld\n", res);
	}
	return 0;
}

C. Tiles

題意:
有這樣的瓷磚:

用來拼\(n \cdot m\)的地板,要求任意相鄰的邊兩邊的顏色不能相同。

思路:
顯然第一個位置可以有四種選擇,並且第一排的后面的每個位置都有兩種選擇,因為不能和前面的邊相同。
那么第一列后面的位置也有兩種選擇,那么剩下的位置都只有一種選擇,因為它們相鄰了兩條邊。
所以答案就是\(4 \cdot 2^{n + m - 2}\)

代碼:

#include <bits/stdc++.h>
using namespace std;
 
#define ll long long
const ll p = 998244353;
 
ll qmod (ll base, ll n) {
	ll res = 1;
	while (n) {
		if (n & 1) {
			res = res * base % p;
		}
		base = base * base % p;
		n >>= 1;
	}
	return res;
}
 
int main() {
	int n, m;
	while (scanf("%d%d", &n, &m) != EOF) {
		printf("%lld\n", qmod(2, n - 1) * qmod(2, m - 1) % p * 4 % p);
	}
	return 0;
}

D. Prime Graph

題意:
給出\(n\)個點,要求構成一個簡單圖,使得邊的總數是素數,並且每個點的度數也是素數。

思路:

  • 首先考慮每個點的度數至少為\(2\),那么先把這些點連成一個環,所有點的度數就是\(2\)了。
  • 再考慮邊的數量是素數,一個顯然的想法是所有數都可以表示成\(2x + 3y\)的形式,所以我們將環中的點分成兩部分,每次各取一個點連邊,就增加一條邊,並且讓兩個度數為\(2\)的點變成度數為\(3\)的。
  • 那么只要滿足我們找一個\(>= n\)的最近的素數\(y\),使得\(y - n \leq \frac{n}{2}\)即可這樣構造。
  • 素數的密度很高,或者\(n\)只有\(1000\)可以打表驗證一下,這樣是可以的。

代碼:

#include <bits/stdc++.h>
using namespace std;
 
#define N 1010
#define pii pair <int, int>
#define fi first
#define se second
int n;
 
bool isprime(int x) {
	for (int i = 2; i < x; ++i) {
		if (x % i == 0) return 0;	
	}
	return 1;
}
 
int main() {
	while (scanf("%d", &n) != EOF) {
		int tot = n;
		for (int i = tot; ; ++i) {
			if (isprime(i)) {
				tot = i;
				break;
			}
		}
		vector <pii> vec;
		for (int i = 2; i <= n; ++i) vec.push_back(pii(i - 1, i));
		vec.push_back(pii(1, n));
		int remind = tot - n;
		int pos = n / 2 + 1; 
		for (int i = 1; i <= remind; ++i) {
			vec.push_back(pii(i, pos));
			++pos;	
		}
		printf("%d\n", tot);
		for (auto it : vec) printf("%d %d\n", it.fi, it.se); 
	}
	return 0;
}

E. Archaeology

題意:
給出一個只包含'a', 'b', 'c'的字符串,保證任意兩個連續的字符都不相同,要求選出一個子序列\(t\)使得它是一個回文串,並且\(|t| \geq \left\lfloor \frac{|s|}{2} \right\rfloor\)

思路:
貪心從兩端取即可。
因為左端的兩個字符和右端的兩個字符,必然會有兩個相等,因為保證了任意兩個連續的字符不同,那么這樣就是說每\(4\)個字符,至少有\(2\)個有貢獻,顯然滿足題目限制。
其實也可以枚舉一樣,看看:
假如左端的\(ab\),那么右端的取值有以下幾種:

  • \(ab\)
  • \(ac\)
  • \(bc\)
    顯然都滿足要求。

代碼:

#include <bits/stdc++.h>
using namespace std;
 
#define N 1000010
#define INF 0x3f3f3f3f
int n, m, f[N][3], g[N][3], nx[3];
char s[N], t[N];
int vis[N];
 
bool ok() {
	m = 0;
	for (int i = 1; i <= n; ++i) if (vis[i]) {
		t[++m] = s[i]; 
	}
	t[m + 1] = 0;
	if (m >= n / 2) {
		printf("%s\n", t + 1);
		return 1;
	}
	return 0;
}
 
int main() {
	while (scanf("%s", s + 1) != EOF) {
		n = strlen(s + 1);
		for (int i = 1; i <= n; ++i) vis[i] = 0;
		nx[0] = nx[1] = nx[2] = 0;
		for (int i = 1; i <= n + 1; ++i) {
			for (int j = 0; j < 3; ++j) {
				g[i][j] = nx[j];
			}
			if (i <= n) {
				nx[s[i] - 'a'] = i;
			}
		}
		nx[0] = nx[1] = nx[2] = n + 1;
		for (int i = n; i >= 0; --i) {
			for (int j = 0; j < 3; ++j) {
				f[i][j] = nx[j];
			}
			if (i > 0) {
				nx[s[i] - 'a'] = i;
			}
		}
		int l = 0, r = n + 1;
		while (l <= r) {
			int Min = INF, pos = -1;
			for (int i = 0; i < 3; ++i) {
				if (f[l][i] < g[r][i] && f[l][i] - l + r - g[r][i] < Min) {
					Min = f[l][i] - l + r - g[r][i];
					pos = i;
				}
			}
			if (pos == -1) break;
			l = f[l][pos];
			r = g[r][pos];
			vis[l] = vis[r] = 1;
		}
		if (l < r - 1) {
			vis[l + 1] = 1;
		}
		if (!ok()) printf("IMPOSSIBLE\n");
	}
	return 0;
}

F1. Short Colorful Strip

題意:
有一個長度為\(n\)的方格紙,現在要求做\(n\)次塗刷操作,每次選擇一個區間將其刷成顏色\(i\),剛開始全都為顏色\(0\),問最后方格紙上第\(i\)格顏色為\(c_i\)的方案數。
\(n = m\)

思路:
\(f[l][r]\)表示完成區間\([l, r]\)的塗刷的方案數。
考慮對於一個區間\([l, r]\),那么我們第一次塗的肯定是\(c_i\)最小的,然后以\(c_i\)最小的那個格子為界,划分成兩邊,令\(pos[i]\)表示當前區間\(c_i\)最小的格子的下標,那么有轉移方程:

\[\begin{eqnarray*} f[l][r] = \sum\limits_{a} \sum\limits_{b} f[l][a - 1] \cdot f[a][pos[i] - 1] \cdot f[pos[i] + 1][i - 1] \cdot f[i +1][r] \end{eqnarray*} \]

注意到划分出兩個區間后,左邊右邊獨立,所以可以分開計算,最后乘起來即可。

代碼:

#include <bits/stdc++.h>
using namespace std;
 
#define ll long long
#define N 510
const ll p = 998244353;
int n, m, a[N];
ll f[N][N]; 
 
void add(ll &x, ll y) {
	x += y;
	if (x >= p) x -= p;
}
 
ll dp(int l, int r) {
	if (l > r) return 1;
	if (f[l][r] != -1) return f[l][r];
	if (l == r) return f[l][r] = 1;
	f[l][r] = 0;
	int pos = l;
	for (int i = l + 1; i <= r; ++i) {
		if (a[i] < a[pos]) pos = i;
	}
	ll L = dp(l, pos - 1), R = dp(pos + 1, r);
	for (int i = l; i < pos; ++i) {
		add(L, dp(l, i) * dp(i + 1, pos - 1) % p);
	}
	for (int i = pos + 1; i <= r; ++i) {
		add(R, dp(pos + 1, i) * dp(i + 1, r) % p);
	}
	return f[l][r] = L * R % p;
}
 
int main() {
	while (scanf("%d%d", &n, &m) != EOF) {
		memset(f, -1, sizeof f);
		for (int i = 1; i <= n; ++i) scanf("%d", a + i);
		printf("%lld\n", dp(1, n)); 
	}
	return 0;
}


免責聲明!

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



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