Educational Codeforces Round 174 (Rated for Div. 2)

B

首先注意到一个连通块最多操作两次,如果大小为1,那么只需要操作一次,那么对于每个颜色,操作次数就是所有连通块中是否有大小\(\ge2\)的,如果有那么就是2,否则是1,枚举最后使用哪个颜色即可

C

注意到值域只有{1,2,3},并且长度至少为3,那么一定是形如1,2,2,....2,3这样的形式,记录三个状态即可

D

当时写的是二分,对于每个位置,假如(i,j)操作是可以的,那么(i,k),\((j \le k)\)肯定也可以,然后就是讨论一下区间的位置即可

不过有更简单的做法,注意到假如s[1]=s[n],那么我们肯定是不管它们的,那么找到第一个\(s[i] \neq s[n+1-i]\)的位置,i和n-i+1至少有一个需要在操作区间中,不妨假设是i(另一个翻转即可),依次检查这些区间即可

#include<bits/stdc++.h>
#define fo(i,a,b) for(ll (i)=(a);(i)<=(b);(i)++)
#define fd(i,a,b) for(ll (i)=(a);(i)>=(b);(i)--)
#define ll long long 
#define db long double 
#define mk make_pair
#define eb emplace_back
#define pi pair<ll,ll>
#define fi first
#define se second
#define lc (o<<1)
#define rc ((o<<1)|1)
using namespace std;
const int N = 2e5 + 5;
const ll inf = 1ll << 60;
const ll mo = 998244353;
string s;
ll n, l, r, mid, p, t[N][26], a[26], b[26], m1, m2, jj, ii, k;
void add(ll & x, ll y) {
	x = (x + y) % mo;
}
bool check(ll l, ll r) {
	ll mn = min(l - 1, n - r);
	if (mn > p) return 0;


	if (r <= m1) {
		if (r < m1 - k) return 0;
		jj = m2 + (m1 - r);
		ii = m2 + (m1 - l);

		fo(i, 0, 25) {
			if (t[ii][i] - t[jj - 1][i] != t[r][i] - t[l - 1][i]) return 0;
		}
		return 1;
	}
	else if (l >= m2) {
		if (l > m2 + k) return 0;
		jj = m1 - (r - m2);
		ii = m1 - (l - m2);

		fo(i, 0, 25) {
			if (t[r][i] - t[l - 1][i] != t[ii][i] - t[jj - 1][i]) return 0;
		}
		return 1;
	}

	fo(i, 0, 25) a[i] = t[r][i] - t[l - 1][i];

	if (m1 - l < r - m2) {
		jj = m1 - (r - m2);
		fo(i, 0, 25) a[i] -= (t[l - 1][i] - t[jj - 1][i]);
	}
	else if (m1 - l > r - m2) {
		ii = m2 + (m1 - l);
		fo(i, 0, 25) a[i] -= (t[ii][i] - t[r][i]);
	}

	fo(i, 0, 25) {
		if (a[i] < 0 || a[i] % 2) return 0;
	}
	return 1;
}
int main() {
	// freopen("data.in", "r", stdin);
	// freopen("data.out", "w", stdout);

	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);

	int T;
	cin >> T;
	while (T--) {
		cin >> s;
		n = s.length();
		s = " " + s;

		p = 0;
		while (p < n / 2 && s[p + 1] == s[n - p]) p++;

		m1 = n / 2, m2 = n / 2 + 1; k = 0;
		while (m2 + k <= n && s[m1 - k] == s[m2 + k]) k++;

		fo(i, 1, n) {
			fo(j, 0, 25) t[i][j] = t[i - 1][j];
			t[i][s[i] - 'a']++;
		}

		if (p == n / 2) {
			cout << 0 << "\n";
			continue;
		}

		// cout << check(9, 18) << "\n";
		// return 0;

		// ll len = n;

		// fo(i, 1, n) fo(j, i + 1, n) {
		// 	if (check(i, j)) len = min(len, j - i + 1);
		// }
		// cout << len << "\n";
		// return 0;




		// cout << check(4, 5);

		// return 0;

		ll ans = n;
		fo(i, 1, n-1) {
			l = 1; r = n - i + 1;
			while (l < r) {
				mid = (l + r) >> 1;
				if (check(i, i + mid - 1)) r = mid;
				else l = mid + 1;
			}

			if (check(i, i + l - 1)) ans = min(ans, l);
	
			// if (ans == 2) {
			// 	cout << i << "\n"; break;
			// }
		}

		cout << ans << "\n";
	}



	return 0;
}
 

E

  • 首先注意到假如有大于2个相同的字母连在一起,中间的是确定的,比如AAAAB,那么中间的2个A,一定是单独的A,我们直接将它们移除,变成AAB
  • 那么现在的序列是连续相同字母不超过2个的串
  • 再注意到,假如我们对于在连续相同的位置进行分割,那么,将会形成若干没有连续相同的串
  • 比如A ABABAB BAB BAA,会分割成
  • A
  • ABABAB
  • BAB
  • BA
  • A
  • 那么对于一个长度为奇数的串来说,无论是用AB还是BA,最后都会剩下一个字母,并且剩下的字母是固定的,我们只需要知道长度即可
  • 假如对于一个偶数长度的串,比如是A开头的,那么我们应该先尽量用AB去填
  • 假如AB没有办法填完偶数长度的AB串,那么就用BA填,但是注意到用BA去填的话,每个串都一定会需要一个单独的A和一个单独的B,为了减少串的个数,我们用AB来做的时候,应该从小到大填。
#include<bits/stdc++.h>
#define fo(i,a,b) for(ll (i)=(a);(i)<=(b);(i)++)
#define fd(i,a,b) for(ll (i)=(a);(i)>=(b);(i)--)
#define ll long long 
#define db long double 
#define mk make_pair
#define eb emplace_back
#define pi pair<ll,ll>
#define fi first
#define se second
#define lc (o<<1)
#define rc ((o<<1)|1)
using namespace std;
const int N = 5e5 + 5;
const ll inf = 1ll << 60;
const ll mo = 998244353;
string t;
char ss[N];
ll n, a, b, ab, ba, sum;
vector<ll> c[3];
void work1(ll & x, ll id) {
	ll s = 0;
	for (auto v : c[id]) s += v;
	for (int i = 0;i < c[id].size();i++) {
		if (x >= c[id][i]) {
			x -= c[id][i];
			s -= c[id][i];
		}
		else {
			s -= x;
			c[id][i] -= x;
			x = 0;

			a -= c[id].size() - i;
			b -= c[id].size() - i;
			sum += s - (c[id].size() - i);
			break;
		}
	}
}
int main() {
	// freopen("data.in", "r", stdin);
	// freopen("data.out", "w", stdout);

	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);

	int T;
	cin >> T;
	while (T--) {
		cin >> t;
		n = t.length();
		t = " " + t;
		cin >> a >> b >> ab >> ba;

		ll mm = 0;
		for (int i = 1, j;i <= n;i = j + 1) {
			j = i;
			while (j < n && t[j + 1] == t[i]) j++;

			if (j > i) {
				ss[++mm] = t[i]; ss[++mm] = t[i];
				if (t[i] == 'A') a -= (j - i - 1);
				else b -= (j - i - 1);
			}
			else {
				ss[++mm] = t[i];
			}
		}

		c[0].clear();
		c[1].clear();

		sum = 0;
		for (int i = 1, j;i <= mm;i = j + 1) {
			j = i;
			while (j < mm && ss[j + 1] != ss[j]) j++;

			if ((j - i + 1) % 2) {
				if (ss[i] == 'A') a--; else b--;
				sum += (j - i) / 2;
			}
			else c[ss[i] - 'A'].push_back((j - i + 1) / 2);
		}

		sort(c[0].begin(), c[0].end());
		sort(c[1].begin(), c[1].end());

		work1(ab, 0);
		work1(ba, 1);

		// cout << sum << " "<<ab<<"\n";

		sum -= min(sum, ab);
		sum -= min(sum, ba);

	
		if (sum > min(a, b)) cout << "No\n";
		else cout << "Yes\n";

	}



	return 0;
}


posted @ 2025-03-01 16:51  gan_coder  阅读(27)  评论(0)    收藏  举报