23.3.3打卡 Codeforces Round #855 (Div. 3) A~E

13 篇文章 0 订阅
12 篇文章 0 订阅

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值