Codeforces Round 855 (Div.3)
Codeforces Round 855 (Div. 3)
2023-03-02 22:35~00:50
比赛网址)
- 本篇题解鸣谢官方思路,代码区大佬思路、空気力学の詩大佬思路和CCSU_梅子酒大佬思路
A.Is It a Cat?
题目解析
- 一个字符串只允许由meow连续的字符构成,不区分大小写,让你判断该字符串是否符合。
- 签到
提交代码
// Problem: A. Is It a Cat?
// Contest: Codeforces - Codeforces Round #855 (Div. 3)
// URL: https://codeforces.com/contest/1800/problem/A
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
while(n--)
{
int m;
cin >> m;
string str;
cin >> str;
for(int i = 0; i < str.size(); i++)
{
str[i] = tolower(str[i]);
}
int flag = 1;
int M = 0, e = 0, o = 0, w = 0;
for(int i = 0; i < str.size(); i++)
{
while(i < str.size() && str[i] == 'm' )
{
M++;
i++;
}
while(M &&i < str.size()&& str[i] == 'e')
{
e++;
i++;
}
while(e &&i < str.size()&& str[i] == 'o')
{
o++;
i++;
}
while(o &&i < str.size()&& str[i] == 'w')
{
w++;
i++;
}
if(i < str.size() || !w || !o || !e || !M)
{
flag = 0;
break;
}
}
if(flag) puts("YES");
else puts("NO");
}
return 0;
}
B.Count the Number of Pairs
题目解析
- 给出一个字符串,可以进行字母大小写转化,操作次数有限,为k次,求操作过后大写小写字母配对的最大数量.
- e.g. abBa, k = 1, 那么本来就有Bb配对,为1个,现在又能操作一次,所以将其中一个a转换为A,那么最终的答案就是2个·。
- 签到。
提交代码
// Problem: B. Count the Number of Pairs
// Contest: Codeforces - Codeforces Round #855 (Div. 3)
// URL: https://codeforces.com/contest/1800/problem/B
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
void solve()
{
int m, k;
cin >> m >> k;
string str;
cin >> str;
map<char, int> ans;
map<char, bool> st;
set<char> cnt;
for(int i = 0; i < str.size(); i++)
{
ans[str[i]]++;
cnt.insert(str[i]);
}
int res = 0;
for(auto c : cnt)
{
// cout << c << " " << ans[c] << "\n";
if(isupper(c) && !st[c])
{
char C = tolower(c);
if(cnt.count(C))
{
st[C] = st[c] = true;
res += (ans[c] > ans[C] ? ans[C]:ans[c]);
if(ans[c] > ans[C])
{
ans[c] -= ans[C];
ans[C] = 0;
}
else
{
ans[C] -= ans[c];
ans[c] = 0;
}
}
}
else if(!st[c])
{
char C = toupper(c);
if(cnt.count(C))
{
res += (ans[c] > ans[C] ? ans[C] : ans[c]);
if(ans[c] > ans[C])
{
ans[c] -= ans[C];
ans[C] = 0;
}
else
{
ans[C] -= ans[c];
ans[c] = 0;
}
}
}
}
// cout << res << "\n";
for(char i = 'a'; i <= 'z'; i++)
{
// cout << i << "\n";
char A = toupper(i);
if(ans[A])
{
int k1 = ans[A] / 2;
if(k1 > k)
{
res += k;
break;
}
else
{
k -= k1;
res += k1;
}
}
if(ans[i])
{
int k1 = ans[i] / 2;
if(k1 > k)
{
res += k;
break;
}
else
{
k -= k1;
res += k1;
}
}
}
cout << res << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while(t--)
{
solve();
}
return 0;
}
C1.Powering the Hero (easy version)
题目解析
- 两种牌,英雄牌的标志是0,奖励牌的值大于0,每次进行按顺序抽取,抽到奖励牌放到类似一个栈中,不过抽到奖励牌也可以选择丢到,抽到英雄牌,可以选择一张顶部的奖励牌,然后这个牌的力量值作为该英雄的力量值,问组建的最大的军队的力量。
- 丢到不丢到可以不考虑,只要把奖励牌放到一个大根堆中即可,每次取出最大的即可。这个思路困难版本的也可过。
提交代码
// Problem: C1. Powering the Hero (easy version)
// Contest: Codeforces - Codeforces Round #855 (Div. 3)
// URL: https://codeforces.com/contest/1800/problem/C1
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
#define int long long
using namespace std;
//读题,读题,读题,很简单的一个大根堆。
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while(t--)
{
int n;
cin >> n;
int ans = 0;
priority_queue<int> q;
for(int i = 0; i < n; i++)
{
int a;
cin >> a;
if(a)
{
q.push(a);
}
else
{
if(q.size())
{
auto res = q.top();
q.pop();
ans += res;
}
}
}
cout << ans << "\n";
}
return 0;
}
C2.Powering the Hero (hard version)
题目解析
- 题意同C1,思路同C1。
提交代码
// Problem: C2. Powering the Hero (hard version)
// Contest: Codeforces - Codeforces Round 855 (Div. 3)
// URL: https://codeforces.com/contest/1800/problem/C2
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// STL一遍过
#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while(t--)
{
int n;
cin >> n;
int ans = 0;
priority_queue<int> q;
for(int i = 0; i < n; i++)
{
int a;
cin >> a;
if(a)
{
q.push(a);
}
else
{
if(q.size())
{
auto res = q.top();
q.pop();
ans += res;
}
}
}
cout << ans << "\n";
}
return 0;
}
D.Remove Two Letters
题目解析
- 给定一个字符串,然后删掉其中两个连续的字符都得到一个新的字符串,问不同新字符串的个数。
- 思维
- 穷举会超时。
提交代码
// Problem: D. Remove Two Letters
// Contest: Codeforces - Codeforces Round 855 (Div. 3)
// URL: https://codeforces.com/contest/1800/problem/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
//穷举超时
void solve()
{
int n;
cin >> n;
set<string> ans;
string s;
cin >> s;
for(int k = 0; k < s.size() - 1; k ++)
{
string res;
for(int i = 0; i < s.size(); i ++)
{
if(k == i || k + 1 == i) continue;
else
{
res += s[i];
}
}
if(!ans.count(res)) ans.insert(res);
}
cout << ans.size() << "\n";
}
//思维正解
void solve1()
{
int n;
cin >> n;
long long ans = 0;
string s;
cin >> s;
for(int i = 2; i < n; i++)
{
if(s[i] != s[i - 2]) ans++;
}
cout << ans + 1 << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while(t--)
{
solve1();
}
return 0;
}
E1.Unforgivable Curse (easy version)
题目描述
- 给定两个字符串,s,t,问通过交换其中字符如果能使s变成t则输出YES,否则输出NO,但是,交换是有条件的,必须满足两个交换字母下标相减绝对值只能为k或者k+1,简单版本把k规定为常数3。
- 首先保证两个的长度相同,而且字符的数量对应相等。
- 判断方法就很多了,可以利用数组统计次数
- 也可以将字符串都sort升序,然后判断字符串是否相等。
- 其次假设满足以上两个条件, k = 3时,进行考虑,
- 当s和t长度为 1时,s必须等于t
- 当s和t长度为 2时,s也必须等于t,因为下标之差小于3
- 当s和t长度为 3时,同理,s=t
- 当s和t长度为 4时,只有首尾可以交换,所以\(s[1] = t[1], s[2] = t[2]\)
- 当s和t长度为 5时,只有中间的那一个不能交换,所以\(s[2] = t[2]\)
- 当s和t长度大于 6时,任何字符都不再受约束了,都可以交换,任何字符可以换到任何位置,贪心,不懂的话,可以从纸上画一下,注意可以移动的步长是 3 和 4。
- 以上是k= 3的情况下,k等于 数都是一个道理。
- 有没有统一的写法,有,n - k ≤ i < k, 就可以判断所有情况
- n - k < k ,2 * k > n,
- n < 2 * k , 说明一定存在点受移动约束,需要判断某些对应位是否相等。
- i一定小于k的原因,就是 下标都是从0开始的,所以k位相当于步长相差k - 0 = k步,所以如果等于k说明一定是可以移动的。同样考虑一点到最右边的距离不可大于k,如果当前下标为i,i一定满足,n - 1 - i < k,下标是从零开始的,所以用n- 1减去 i,所以n - 1 - k < i,所以就会有n - k ≤ i。
- 由于考虑的k是任意自然数,所以对于困难版本也就解决了。
提交代码
// Problem: E1. Unforgivable Curse (easy version)
// Contest: Codeforces - Codeforces Round 855 (Div. 3)
// URL: https://codeforces.com/contest/1800/problem/E1
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
void solve()
{
int n, k;
cin >> n >> k;
string s, t;
cin >> s >> t;
string temps = s;
string tempt = t;
sort(temps.begin(), temps.end());
sort(tempt.begin(), tempt.end());
if(temps != tempt)
{
cout << "NO\n";
return ;
}
for(int i = 0; i < n; i++)
{
if((n - k <= i && i < k) && s[i] != t[i])
{
cout << "NO\n";
return ;
}
}
cout << "YES\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while(t--)
{
solve();
}
return 0;
}
E2.Unforgivable Curse (hard version)
题目解析
- 题意同E1,不过k不是定值,k可以是任意正整数。
- 思路同E1。
提交代码
// Problem: E2. Unforgivable Curse (hard version)
// Contest: Codeforces - Codeforces Round 855 (Div. 3)
// URL: https://codeforces.com/contest/1800/problem/E2
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
void solve()
{
int n, k;
cin >> n >> k;
string s, t;
cin >> s >> t;
string temps = s;
string tempt = t;
sort(temps.begin(), temps.end());
sort(tempt.begin(), tempt.end());
if(temps != tempt)
{
cout << "NO\n";
return ;
}
for(int i = 0; i < n; i++)
{
if((n - k <= i && i < k) && s[i] != t[i])
{
cout << "NO\n";
return ;
}
}
cout << "YES\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while(t--)
{
solve();
}
return 0;
}
F.Dasha and Nightmares
题目解析
- 给出一组字符串,问两个字符串拼接满足如下四个要求的字符串数量为多少
- 要求1 新字符串是由两个字符串拼接而成的
- 要求2 新字符串字符个数必须是奇数个
- 要求3 新字符串的不同字符个数必须是25个
- 要求4 新字符串的所有字符的个数必须是奇数个
- 思路来源:空気力学の詩&&CCSU_梅子酒
- 先考虑字符出现次数为奇数这个条件,不难想到可以状压每个字符出现的次数的奇偶性
- 由于奇偶性的加减类似于异或,因此我们可以通过用目标状态异或当前状态来得到与之匹配的另一个状态
- 异或满足25个字符出现,就是已经保证了所有字符出现的个数是奇数个,所有字符都是奇数个,那么25是奇数,奇数个奇数也是奇数。
- 用二进制,将每个字符串转化为一个长度为 26 的二进制数,字符 ch 的个数, 奇数 = 1 ,偶数 = 0 ,例如 str = "a",二进制串 = 1000, str = "ab" = 1100 , str = "aab" = 0100 …
- 但是必须只有 25 个,但是偶数对应 0 , 那么不知道该字符是否有,因为没有该字符为 0 也对应 0 。例如枚举字符 a 没有, 但字符串 str="aa" ,那么该字符串代表的二进制为全 0,就可以和字符串 "b ∼ z" 拼接,但拼接后有26 个字母,显然不合法,所以需要用一个vis数组统计某一个字符是否出现过。
提交代码
// Problem: F. Dasha and Nightmares
// Contest: Codeforces - Codeforces Round 855 (Div. 3)
// URL: https://codeforces.com/contest/1800/problem/F
// Memory Limit: 512 MB
// Time Limit: 4000 ms
//
// Powered by CP Editor (https://cpeditor.org)
//注意优先级,((1 << 26) - 1) != (1 << 26 -1)
//位运算,考虑奇偶时,位运算的 ^ 异或操作。
//还有一个知识点,判断两个数是否都为奇数,直接让两个数相乘看是否为奇数。
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int vis[26], cnt[26], n, compare[26];
unordered_map<int,int> num[26];
long long ans;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
string s;
cin >> n;
for(int i = 0; i < 26; i++) compare[i] = ((1 << 26) - 1) ^ (1 << i);
for(int i = 0; i < n; i++)
{
cin >> s;
for(int j = 0; j < 26; j++) vis[j] = cnt[j] = 0;
for(int j = 0; j < s.size(); j++) vis[s[j] - 'a'] = 1, cnt[s[j] - 'a'] ^= 1;
int current = 0;
for(int j = 0; j < 26; j++) current |= (cnt[j] << j);
for(int j = 0; j < 26; j++) if(!vis[j]) num[j][current]++;
for(int j = 0; j < 26; j++) if(!vis[j]) ans += num[j][current ^ compare[j]];
}
cout << ans << "\n";
return 0;
}