https://codeforces.com/contest/1800
A题
题意
判断一个字符串里是否有meow(大小写均可), 其中
字符串必须以仅包含字符“m”或“M”的非空序列开头
它必须紧跟仅由字符“e”或“E”组成的非空序列
它必须紧跟仅由字符“o”或“O”组成的非空序列
它后面必须紧跟仅由字符’w’或’W’组成的非空序列,这个序列结束字符串,在它之后紧接着是字符串结束
也就是说, 形如MMMEEEEEOOOWWW的字符串也是合法的
题解
解法一:
因为大小写均可, 所以我们需要将字符串全部字母改变为小写或者大写, 然后去重就好了
解法二:
直接按照题目的要求模拟, if判断m后面跟的是m或者e, e后面跟的只能是e或者o… …
代码:
仅给出解法一的代码, 解法二代码太屎
void solve()
{
cin>>n>>str;
string s;
for(int i=0;i<n;i++)
if(str[i]>='a') str[i]-=32;
for(int i=0;i<n;i++)
if(str[i]!=str[i+1]) s+=str[i];
if(s=="MEOW") yes
else no
return;
}
B
题意:
给出一串字符串, 可以将其中间的字符随意变为大小写, 当有一个小写字母对应其大写字母时(必须是相同的字母), 称为一节字符, 问最大字母的数量可以为多少
题解:
典型的贪心, 先将成节的字符去掉, 剩下单个小写(或者大写)的数量/2就是最多可以变成的节数
代码:
rep(i,1,n)就是for(long long i=1;i<=n;i++)
懒得改了
void solve()
{
R n>>m>>str;
vector<ll>mp('z'+10,0);
repr(i,0,n)
mp[str[i]]++;
ans=0;
rep(i,'a','z')
{
cnt=min(mp[i-32],mp[i]);
ans+=cnt;
mp[i-32]-=cnt;
mp[i]-=cnt;
}
ant=0;
rep(i,'a','z')
{
ant+=mp[i]/2;
ant+=mp[i-32]/2;
}
cout<<min(ant,m)+ans<<endl;
return;
}
C题
题意
一个牌库, 有两种牌, 每回合抽一张牌, 有可能是英雄牌也有可能是增幅牌
每当抽到增幅牌时, 可以选择放在栈顶或者直接弃牌, 抽到英雄牌时, 将栈顶的增幅给予英雄, 问, 所有英雄加起来最大的增幅是多少?
ps: 英雄牌数值默认为0
题解
很明显, 每当我们抽到英雄牌时, 没有抽到的增幅牌是与当前英雄牌没有关系的, 所以我们只能向前搜, 贪心前面最大的数字
C1题解:
在C1中, 时间复杂要求度低, 我们可以使用暴力的思维来解答这题, 每当抽到英雄牌时, 向前搜, 找到max赋值给英雄即可
C2题解:
因为时间复杂度要求高, 没有办法使用暴力贪心的思维来解答, 可以使用优先队列(多重集也可以)来贪心
考虑优先队列是否能够贪心这题
首先当英雄卡>=增幅卡时, 对于增幅卡没得选, 只能使用全部增幅卡, 此时使用优先队列并无大碍, 只有获取英雄获取增幅卡的顺序不一样, 此题并不要求顺序严格遵循, 可以用
当英雄卡<增幅时, 首先对于每个英雄卡都能保证有增幅卡能够选, 然后选贪心当前回合数最大的增幅卡给每个英雄, 因为英雄至少可以有一个增幅卡可以选, 而且对于其他选不上的完全可以弃掉, 这里并不能弃掉, 因为有可能会被后面的英雄卡给选上, 但因为不要求顺序严格遵循, 只需要看最终之和, 所以这里也完全可以忽视
代码
这里给出C2代码, C1代码过于简单
void solve()
{
cin>>n;
rep(i,1,n) R arr[i];
priority_queue<ll>q;
ans=0;
rep(i,1,n)
{
if(arr[i]==0)
{
if(q.size()==0) continue;
ans+=q.top();
q.pop();
}else
q.push(arr[i]);
}
cout<<ans<<endl;
return;
}
D题
题意:
给你一个字符串, 可以任意去掉其中连续的两个字母, 问去掉两个连续的字母之后有多少个不同的结果
题解:
一眼我是STL大神, 直接map存字符串结果荣获mle5
7
abacaba
观察这个样例
遍历一遍下来结果是
**代表被删除的位置
**acaba 删除ab
a**caba 删除ba
ab**aba 删除ac
aba**ba 删除ca
abac**a 删除ab
abaca** 删除ba
将相同结果的放在一起观察
**acaba
a**caba
ab**aba
aba**ba
abac**a
abaca**
观察发现, 在相同结果的子串下, 被删除的两个位置相邻的元素是一样的
大胆尝试就能成功!
然后成功了
当然这种方法如果想不到的话你可以用字符串哈希防止内存爆掉
代码
void solve()
{
cin>>n>>str;
ans=0;
cnt=0;
str=" "+str;
map<string,ll>mp;
rep(i,3,n)
if(str[i]==str[i-2]) ans++;
ans++;
cout<<n-ans<<endl;
return;
}
E题(直接讲E2)
题意:
给两个字符串s1, s2和k值, 可以在s1中交换距离为k或者k+1的的字符, 问能不能使得s1==s2
题解:
个人感觉1759C比这题更简单
https://codeforces.com/contest/1759/problem/C
思维是一样的, 1759C还需要考虑移动的步数, 这题只需要考虑能不能交换就好了
直接挪用1759C的结论, 看边界与k的距离关系(一定要画图!)
然后看看有没有出现别的字母就好了
代码:
void solve()
{
cin>>n>>m;
string s1,s2;
cin>>s1>>s2;
if(s1==s2)
{
yes
return;
}
s1=" "+s1;
s2=" "+s2;
map<ll,ll>mp1;
map<ll,ll>mp2;
rep(i,1,n)
{
mp1[s1[i]]++;
mp2[s2[i]]++;
}
if(mp1!=mp2)
{
no
return;
}
rep(i,1,n)
{
if(s1[i]!=s2[i]&&(i+m>n&&i<=m))
{
no
return;
}
}
yes
return;
}