Codeforces Round #855 (Div. 3) (A-F复盘)


链接
传送门
题解

A.Is It a Cat?【字符比较、STL】

分析1
这题要求检查这个字符串是若干个连续m,若干个连续的e,若干个连续的o,若干的连续的w。我原先的想法是一段一段检查。
实现1

#include <bits/stdc++.h>
#define ll long long
#define ls (u << 1)
#define rs (u << 1 | 1) 
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 8005;
//int sum[N], cnt[N], vis[N];
void solve() {
	int n;
	cin >> n;
	string s;
	cin >> s;
	if (s[0] != 'M' && s[0] != 'm') {//第一个是m或M
		cout << "NO\n";
		return;
	}
	int p = 0;
	while (p + 1 < n && (s[p] == 'm' || s[p] == 'M')) p++;//跳过M
	if (s[p] != 'E' && s[p] != 'e') {//如果不是E
		cout << "NO\n";
		return;
	}
	while (p + 1 < n && (s[p] == 'e' || s[p] == 'E')) p++;//跳过E
	if (s[p] != 'O' && s[p] != 'o') {
		cout << "NO\n";
		return;
	}
	while (p + 1 < n && (s[p] == 'O' || s[p] == 'o')) p++;//跳过O
	if (s[p] != 'W' && s[p] != 'w') {
		cout << "NO\n";
		return;
	} 
	while (p + 1 < n && (s[p] == 'w' || s[p] == 'W')) p++;//跳过W
	if (p + 1 != n || (s[p] != 'w' && s[p] != 'W')) {//最后要停在最后一个w上
		cout << "NO\n";
		return;
	}
	cout << "YES\n";
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T = 1;
	cin >> T;
	while (T--) solve();
}

分析2
STL里面有一个非常有用的函数、unique函数,时间复杂度是O(n),它的原理是把下一个不相同的元素覆盖掉前面的元素。
实现2

#include <bits/stdc++.h>
#define ll long long
#define ls (u << 1)
#define rs (u << 1 | 1) 
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 26;
int cnt1[N], cnt2[N];
void solve() {
	int n;
	cin >> n;
	string s;
	cin >> s;
	for (auto &x : s) {
		if (x >= 'A' && x <= 'Z') x += 32;
	}
	s.erase(unique(s.begin(), s.end()), s.end());
	cout << (s == "meow" ? "YES\n" : "NO\n");
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T = 1;
	cin >> T;
	while (T--) {
		solve();
	}
}

B.Count the Number of Pairs 【贪心】

分析
这到题我们只需要统计大小写字母的数目,把先配对的统计起来,没有配对的可以花费一次操作把两个相同的字母(多出来的)转换成一对,把最大的可能的对数求出来,和最大的操作次数求出来,取小的。
实现

#include <bits/stdc++.h>
#define ll long long
#define ls (u << 1)
#define rs (u << 1 | 1) 
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 26;
int cnt1[N], cnt2[N];
void solve() {
	int n, k;
	for (int i = 0; i < 26; i++) cnt1[i] = cnt2[i] = 0;
	cin >> n >> k;
	string s;
	cin >> s;
	for (auto x : s) {
		if (x >= 'a' && x <= 'z') cnt1[x -'a']++;
		if (x >= 'A' && x <= 'Z') cnt2[x - 'A']++;
	}
	int ans = 0, need = 0;
	for (int i = 0; i < 26; i++) {
		ans += min(cnt1[i], cnt2[i]);
		need += (max(cnt1[i], cnt2[i]) - min(cnt1[i], cnt2[i])) / 2; 
	}
	ans += min(need, k);
	cout << ans << '\n';
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T = 1;
	cin >> T;
	while (T--) solve();
}

C1&C2. Powering the Hero【贪心、优先队列】

分析
这里十分滴的简单,注意数组不要开小了,注意不要负边界了越界了,从左到右,每次取当前的最大的值,所有可以取的数的最大值。为什么呢?前面的0先取前面最大值,然后后面的零也取前面的最大值,xxxx0xxxx0如果说最大值在前面的x里,第一个0会取到,后面的取到次大的,不可能有更大的,如果说最大值在后面的x里,后面的取到最大值,前面也只能取前面区间的最大值,所以也不可能有更大的值。一般地理解,对于第一个而言,就是取最大的,没有问题,如果说后面的0也取这个值,那么前面的零要换别的值,但是这个选择范围就变小了,反正最大的值一定被取,所以主要看另一个值的大小,对于后面的而言,选择的范围更大,另一个值就可以更大。 对于更多后面的值,如果一定要取前面已经取过的最大值,那么会导致另一个值的选择范围变小,使得总体的值更小,所以就取当前的最大。
实现

 #include <bits/stdc++.h>
#define ll long long
#define ls (u << 1)
#define rs (u << 1 | 1) 
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 2e5 + 5;
int a[N], vis[N];
void solve() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) cin >> a[i], vis[i] = 0;
	ll ans = 0;
	priority_queue<int> q;
	for (int i = 1; i <= n; i++) {
		if (a[i]) q.push(a[i]);
		if (a[i] == 0 && !q.empty()) {
			ans += q.top();
			q.pop();
		} 
	}
	cout << ans << '\n';
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T = 1;
	cin >> T;
	while (T--) solve();
}

D.Remove Two Letters【字符哈希(没必要)、算贡献】

分析
这道题也是非常地简单,考虑贡献,看看有多少的字符是相同的,如果长度是n,总共生成的字符串是n-1,看看有多少个字符相同即可
aaabc
aaabc
aaabc
aaabc
对于与相邻的两次操作,什么时候出现新的字符串呢?例如第一和第二个字符串,共同都删除一个a,一和二的变化相当于还给一个a,然后删掉一个a,所以字符是一样的。cnt–。对于二和三的变话,相当于还给一个a,删掉一个b,产生了新的字符串,cnt不变。后面会不会还出现和前面一样的字符串呢?这个新的字符串保证和相邻操作产生的字符串,后面的产生的字符串和这个新的字符串又不一样,那么前面产生的新的字符串和后面产生的字符串会不会一样呢?
abcdef
abcdef
abcdef
abcdef
abcdef
对于每次产生的新的字符串,到当前位置的变化都会被前缀记录下来,前缀的信息保证了后面的产生的新的字符不会相同。因为前面不同的部分已经存在,例如第三个字符和第一个字符不同,因为a和b不同就是因为a多删除了某个字符,而对于后面的来说,所有的字符都存在的,所以必定不同。

#include <bits/stdc++.h>
#define ll long long
#define ls (u << 1)
#define rs (u << 1 | 1) 
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 2e5 + 5;
int a[N], vis[N];
void solve() {
	int n;
	cin >> n;
	string s;
	cin >> s;
	char lc = s[0], rc = s[0];
	int ans = n - 1;
	for (int i = 1; i + 1 < n; i++) {
		if (lc == s[i + 1]) ans--;
		lc = s[i];
		rc = s[i + 1];
	}
	cout << ans << '\n';
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T = 1;
	cin >> T;
	while (T--) solve();
}

E1&E2. Unforgivable Curse【联通图、找结论】

分析
这道题的结论是,在字符数一样的情况下,无法移动的点的相同才能YES,否则NO。
为什么?
abacaba;
首先一个简单的情况,n>= 2*k,第一个字符可以进k+1退k,一直到 k ,所以对于任意的第
x个字符 x % k = 0, 1,…k - 1都有,所以第一个字符可以移动到任意位置,和所有可以移动的字符联通,如果联通的话,就可以任意排列这些字符。
如果n<=k就无法移动,k<n< 2 * k的话,第一个字符是一定可以移动的,
1 2 …………k…………n
对于x < k + 1&& x > n - k这部分是无法移动的
只需证明1, 2, 3, n - k - 1以及k + 1…………n是可以移动的
设n = k+d, d < k
x < k + 1, x > d,至少有一个k
1, 2, 3, d - 1, k + 1, k + 2, k …k + d
1-k+1,不能再移k了
1-k+2,
k+2-2
2 - k + 3
k + 3 - 3
依次类推可以证明两侧两两联通。
实现

#include <bits/stdc++.h>
#define ll long long
#define ls (u << 1)
#define rs (u << 1 | 1) 
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 26;
int cnt1[N], cnt2[N];
void solve() {
	int n, k;
	cin >> n >> k;
	string s, t;
	cin >> s >> t;
	for (int i = 0; i < 26; i++) cnt1[i] = cnt2[i] = 0;
	for (auto x : s) cnt1[x - 'a']++;
	for (auto x : t) cnt2[x - 'a']++;
	for (int i = 0; i < 26; i++) {
		if (cnt1[i] != cnt2[i]) {
			cout << "NO\n";
			return;
		}
	}
	if (n >= 2 * k) cout << "YES\n";
	else {
		for (int i = 0; i < n; i++) {
			if (i < k && n - 1 - i < k && s[i] != t[i]) {
				cout << "NO\n";
				return;
			}
		}
		cout << "YES\n";
	}
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T = 1;
	cin >> T;
	while (T--) {
		solve();
	}
}

F.Dasha and Nightmares【状压、哈希】

分析
这里利用二进制来记录字符的状态,用哈希的方法来记录解的数量。详细说明在注释里。
实现

#include <bits/stdc++.h>
#define ll long long
#define ls (u << 1)
#define rs (u << 1 | 1) 
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int N = 2e5 + 5;
int x[N], y[N];
void solve() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		string s;
		cin >> s;
		for (auto u : s) {
			x[i] ^= 1 << u - 'a';//x[i]每位存储第i个字符各个字符出现了奇数次还是偶数次
			y[i] |= 1 << u - 'a';//y[i]每位存储是否出现了各个字符 
		}
	}
	ll ans = 0;
	for (int i = 0; i < 26; i++) {
		map<int, int> cnt;
		int z = (1 << 26) - 1;//全有字符,全奇数次1111……26个 
		z ^= 1 << i;//去掉某个字符101111111... 
		for (int j = 1; j <= n; j++) {
			if (!(y[j] & (1 << i))) {//如果有某个字符缺失的话
				ans += cnt[z ^ x[j]];//
				/*x[i]在1<<i位处的字符是没有的, 
				比如i是1
				那么可能的x[j]是1010101001100,z是1011111111111
				得到0001010110011刚好相反的字符状态,如果有某个这样的字符状态存在就加到ans里
				这两个拼接后就是1011111111111符合要求 
				*/
				cnt[x[j]]++;//记录这个字符状态 
			}
		}//这里要求无序对,也就是求组合,每个j都和j前面的数配对 
	}//like 1 2 3求所有的组合数,3 - 2, 3 - 1, 2 - 1
	cout << ans << '\n'; 
}
int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	int T = 1;
//	cin >> T;
	while (T--) {
		solve();
	}
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值