Educational Codeforces Round 166(A-D題解)

_yimg發表於2024-06-03

Educational Codeforces Round 166(A-D題解)

Educational Codeforces Round 166

2024-06-03 —yimg

A

簽到題

程式碼:

#include<bits/stdc++.h>
using namespace std;
void work()
{
	int n;
	cin >> n;
	string s;
	cin >> s;
	int pos = 0;
	int g = 1;
	for(; pos < s.length(); ++pos){
		if(s[pos] >= 'a') break;
		if(pos && s[pos] < s[pos - 1]){
			g = 0;
		}
	}
	int ppp = pos;
	for(; pos < s.length(); ++pos){
		if(s[pos] <= '9' && s[pos] >= '0') break;
		if(pos != ppp && pos != s.length() && s[pos] < s[pos - 1]){
			g = 0;
		}
	}
//	cout << pos << '\n';
	if((!g) || pos != s.length()){
		cout << "NO\n";
	}
	else{
		cout << "YES\n";
	}	
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
		work();
} 

B

題意:

給定長度為n的陣列a 和 長度為n + 1的陣列b, 將a變成b,問至少幾步操作

有如下幾種操作

  • 任意位置+1 或 -1
  • 選擇任意元素複製到a陣列末尾

思路:

對頭n位我們需要的運算元是\(\sum_{1}^{n} \left| a_i - b_i \right|\)

對於$ b_{n+1}$ 複製要一次操作, 若之前在頭n個數執行操作1時出現過則不用多餘操作

否則取最接近的$ a_i $ 或 $ b_i $ 執行操作1

程式碼:

#include<bits/stdc++.h>
using namespace std;
void work()
{
	int n;
	cin >> n;
	vector<int> a(n + 5);
	vector<int> b(n + 5);
	for(int i = 1; i <= n; ++i)	cin >> a[i];
	for(int i = 1; i <= n + 1; ++i) cin >> b[i];
	long long ans = 0;
	int x = b[n + 1], minn = 0x3f3f3f3f;
	for(int i = 1; i <= n; ++i){
		ans += abs(a[i] - b[i]);
		if(x >= a[i] && x <= b[i] || x >= b[i] && x <= a[i]) minn = 0;
		else minn = min(abs(a[i] - x), min(abs(b[i] - x), minn));
	}
	cout << ans + minn + 1 << '\n';
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
		work();
} 

C

題意:

給定 $ n + m + 1$ 個數對$ { a_i, b_i } $ , 分別求去除第i個數對, 之後的貪心操作結果

貪心操作:我們選取n 個a陣列的值,m個b陣列的值,對剩餘元素按從1到n + m + 1 的序號順序進行選取,

若n 和 m 都沒有選滿則根據$ max(a_i, b_i)$ 選取,若有一邊選滿則剩下的 哪邊沒選滿選哪邊, 求這次操作選取的數的和

思路:

刪除操作會影響的只可能有特定的1個數對,即第一個選不到自身max的數對

將每個數對,我們按他們的a, b 較大值進行分組(兩組)

對於沒選滿的一邊的數對, 我們可以選其max,

對於選滿的一邊,按編號頭 k 個(k 為本組的最大選取數n or m), 一定可以選其大值,k + 2及之後的數對只能被迫選擇 , 唯一會因為刪除而改變選擇的,只有第k + 1對數

  • 刪沒選滿的一邊:直接減去刪掉的數

  • 刪選滿的一邊:

    • 刪 k + 1 及 之後的數, 直接減去
    • 刪 頭 k 個數, 將第k + 1個的選擇取反

程式碼:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void work()
{
	int n, m;
	cin >> n >> m;
	vector<int> a(n + m + 5), b(n + m + 5);
	for(int i = 1; i <= n + m + 1; ++i) cin >> a[i];
	for(int i = 1; i <= n + m + 1; ++i) cin >> b[i];
	vector<vector<int>> f, s;
	vector<int> f_id, s_id;
	vector<ll> d(n + m + 5);
	ll ans = 0;
	for(int i = 1; i <= n + m + 1; ++i){
		if(a[i] > b[i]) f.push_back({a[i], b[i]}), f_id.push_back(i);
		else s.push_back({a[i], b[i]}), s_id.push_back(i);
	}
	int g = 1;
	if(s.size() > m){
		swap(f, s);
		swap(f_id, s_id);
		swap(n, m);
		g = 0;
	}
	{
		for(auto i : s) ans += i[g];
		for(int i = 0; i < n; ++i) ans += f[i][g ^ 1];
		for(int i = n; i < f.size(); ++i) ans += f[i][g];
		for(int i = 0; i < s.size(); ++i)
			d[s_id[i]] = ans - s[i][g];
		for(int i = n; i < f.size(); ++i)
			d[f_id[i]] = ans - f[i][g];
		ans += f[n][g^1] - f[n][g];
		for(int i = 0; i < n; ++i)
			d[f_id[i]] = ans - f[i][g^1];
	}
	for(int i = 1; i <= n + m + 1; ++i)
		cout << d[i] << " ";
	cout << '\n';
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
		work();
} 

D

題意:

能完成括號匹配的括號序列為正常括號序列,問給定正常括號序列的好子串有多少個

好子串 : 將該子串其中的所有括號翻轉(左變右,右變左)之後的括號序列依舊是正常序列

思路:

對於括號匹配問題常常可以用字首和解決問題,左括號+1, 右括號-1, 我們根據字首和統計答案,

字首和相等位置之間的左右括號數量相等,但是像是 ()並不能翻轉 , 本題多一個翻轉後有依舊保證合法的限制,分析一下限制條件

若一個括號序列是好序列則滿足:

  • $ \forall i \in n, pre_i \ge 0$
  • $ pre_n = 0$

若一個子串為好子串則滿足:

  • $ \forall i \in \left[l, r\right], pre_{l-1} \le pre_i - pre_{l - 1}$
  • $ pre_r = pre_{l-1}$

對於每個位置我們可以先把不合法的字首刪掉再進行統計,因為一個字首在一個位置不合法,則此字首在之後的位置需要從0重新統計。

程式碼:

#include<bits/stdc++.h>
using namespace std;
void work()
{
	string s;
	cin >> s;
	map<int, int> cnt;
	int b = 0;
	long long ans = 0;
	cnt[b] = 1;
	for(auto& i : s){
		b += (i == '(' ? +1 : -1);
//		Flase(TLE) :
//		for(auto& j : cnt){
//			if(j.first * 2 < b) j.second = 0;
//			else break;
//		}
		while((!cnt.empty()) && cnt.begin() -> first * 2 < b)
			cnt.erase(cnt.begin());
		ans += cnt[b]++;
	}
	cout << ans << '\n';
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
		work();
}

相關文章