codeforces #550 div3 A-G

本文提供了六道编程竞赛题目的解题思路与代码实现,包括字符串处理、贪心算法、图论和二分图等问题,详细解析了每道题的解决策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

比赛的时候只做出了A-D(太菜 ),然后到现在才补掉了这套题(太懒 ),以下是各题简单叙述,前四题代码就不贴了。

A

Diverse Strings

题目大意

对于给定的字符串,如果是由一段连续的不重复的字母组成,则输出“yes”。

解题思路

直接排序后,遍历检查即可。

B

Parity Alternated Deletions

题目大意

给出n个数,每次可以任意删除一个与上次不同奇偶性的数字(第一次可以随便选),问最后剩余的数字的和最小是多少。

解题思路

统计出序列中奇数和偶数的个数a,b,然后分情况:

  1. abs(a-b)<=1 输出0即可。
  2. a-b>1,说明会剩下a-b-1个奇数,找出最小的那a-b-1个奇数即可。
  3. b-a>1,说明会剩下b-a-1个偶数,找出最小的那b-a-1个偶数即可 。
    注意开longlong

C

Two Shuffled Sequences

题目大意

给出n个数,问能否拆成两个序列,一个严格递增,一个严格递增(可以任意重排)。任意排列这点就大大简化问题了。

解题思路

考虑到可以任意排序,以及严格这两个关键点,读入的时候用一个桶记录所有数字出现的次数。

  1. 某个数字出现次数大于3说明肯定无解(必然有一个序列会出现两个数字相等的情况)。
  2. 某个数字出现次数等于2,分别放在两个序列即可。
  3. 出现一次的数,随便放即可。(长度为0或1的序列可被任意认为递增或者递减)。

D

Equalize Them All

题目大意

给出n个数字的序列,每次可以选择相邻的两个元素,使其中一个元素加上或者减去这两个元素差的绝对值,询问最少需要几次操作,使得所有数字相等,并输出每次操作。ai=ai±|ai−aj|。

解题思路

显然的 贪心题,先找出次数出现最多的那个元素的位置(用桶数组来维护,同C题),然后从那个位置分别向两端扩展,每次让边上的一个元素与它相等即可。

E

Median String
看F题过的人比较多,就没看E这道字符串题,不过感觉挺简单的 。。。

题目大意

给出两个字符串,让你给出排在两个字符串字典序中间的字符串。

解题思路

把字符串当作一个26进制数,由于长度达到2e5,所以需要用大数模拟。从后往前遍历,对于第i位,如果ai+bi是偶数,直接除2即可,如果是奇数,就要向后一位进13(26/2),然后处理一下后一位的进位(/26,%26)。(想想十进制下的奇数除以2)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int N = 2e5 + 5;
char s[N], t[N];
int ans[N];
int main()
{
    int k;
    scanf("%d%s%s",&k,s,t);
    for(int i=k-1;i>=0;i--)
    {
        int a = s[i] - 97, b = t[i] - 97;
        ans[i] = a + b;
        if(ans[i]&1)
        {
            ans[i] = (ans[i]-1) >> 1;
            ans[i+1] += 13;
            ans[i] += ans[i+1]/26;
            ans[i+1] %= 26;
        }
        else ans[i] >>= 1;
    }
    for(int i=0;i<k;i++) printf("%c",ans[i]+97);
    puts("");
    return 0;
}

F

Graph Without Long Directed Paths

题目大意

给出n个点m条边的无环图,问你能否构造出一个有向图(将每条给出的双向边改成有向边),使得任意两点间距离不能大于等于2。

解题思路

二分图判定的染色法,对于一个顶点,不可能同时有入度和出度,要么只有入边,要么只有出边,所以只需要dfs对每一个顶点染色(1代表只有入度,-1代表只有出度)。
应该用vector存图的,然而我强行用链式前向星,没法记录编号,所以代码很丑陋。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int N = 2e5 + 5;
int n, m, cnt, head[N], color[N], ans[N];
bool flag = true;
struct node
{
    int to, next, dir, id;
}e[N<<1];
void add(int u,int v,int w,int id)
{
    e[++cnt].next = head[u];
    e[cnt].to = v;
    e[cnt].dir = w;
    e[cnt].id = id;
    head[u] = cnt;
}
void dfs(int u,int col)
{
    if(!flag) return;
    color[u] = col; 
    for(int i=head[u];i;i=e[i].next)
    {
        int v = e[i].to;
        if(color[v]==col)
        {
            flag = false;  //全局变量判断无解的情况
            return;
        }
        int d;  //奇怪的分类讨论
        if(!e[i].dir&&col==1) d = 1;
        else if(!e[i].dir&&col==-1) d = 0;
        else if(e[i].dir&&col==1) d = 0;
        else d = 1;
        ans[e[i].id] = d;  //这句话不能放在if(!color[v])里面,因为这个一直wa
        if(!color[v]) dfs(v,-col);
        if(!flag) return;
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int u, v;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v,0,i);
        add(v,u,1,i);
    }
    dfs(1,1);
    if(!flag) puts("NO");
    else
    {
        puts("YES");
        for(int i=1;i<=m;i++) printf("%d",ans[i]);
        puts("");
    } 
    return 0;
}

G

Two Merged Sequences
C的强化版,不能重排了。

题目大意

对于给定的n个数组成的序列,问能否按照原序拆成一个严格递增,一个严格递减的序列。cf给的标签是贪心和dp。

解题思路

如果是dp的话,用dp[i][0]记录第i个数字放在升序序列中时,此时降序序列的最小元素的大小,dp[i][1]记录第i个数字放在降序序列中时,此时升序序列的最大元素的大小,然后转移即可。(有点绕)当i放在升序序列时,a[i]就是升序序列的最大元素,所以只需要记录降序序列即可,do[i][1]同理。
考虑贪心,每次也是维护升序序列的最大值up和降序序列的最小值down,然后讨论。

  1. a[i]>up&&a[i]>down 只能放在升序序列,那就放呗,然后更新up=a[i]
  2. a[i]<down&&a[i]<up 只能放在降序序列,那也放呗,然后down=a[i]
  3. a[i]>up&&a[i]<down 两个地方都能放,那考虑后一个元素(给后面留条路),如果a[i+1]大于a[i],就放在升序,否则放在降序。(核心)
  4. 哪都放不了,那就输出NO。
    下面是贪心代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int N = 2e5 + 5;
int n, a[N];
bool ans[N], flag = true;
int main()
{
    int pos = 0, minn = 0x3f3f3f3f;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    int up = -1, down = N;
    for(int i=1;i<=n;i++)
    {
        if(a[i]<down&&a[i]>up)
        {
            if(a[i+1]>a[i]||i==n)
            {
                up = a[i];
                ans[i] = 0;
            }
            else
            {
                down = a[i];
                ans[i] = 1;
            }
        }
        else if(a[i]<down)
        {
            down = a[i];
            ans[i] = 1;
        }
        else if(a[i]>up)
        {
            up = a[i];
            ans[i] = 0;
        }
        else
        {
            flag = false;
            break;
        }
        
    }
    if(!flag) puts("NO");
    else 
    {
        puts("YES");
        for(int i=1;i<=n;i++) printf("%d ",ans[i]);
        puts("");
    }
    return 0;
}
内容概要:本文深入探讨了Kotlin语言在函数式编程和跨平台开发方面的特性和优势,结合详细的代码案例,展示了Kotlin的核心技巧和应用场景。文章首先介绍了高阶函数和Lambda表达式的使用,解释了它们如何简化集合操作和回调函数处理。接着,详细讲解了Kotlin Multiplatform(KMP)的实现方式,包括共享模块的创建和平台特定模块的配置,展示了如何通过共享业务逻辑代码提高开发效率。最后,文章总结了Kotlin在Android开发、跨平台移动开发、后端开发和Web开发中的应用场景,并展望了其未来发展趋势,指出Kotlin将继续在函数式编程和跨平台开发领域不断完善和发展。; 适合人群:对函数式编程和跨平台开发感兴趣的开发者,尤其是有一定编程基础的Kotlin初学者和中级开发者。; 使用场景及目标:①理解Kotlin中高阶函数和Lambda表达式的使用方法及其在实际开发中的应用场景;②掌握Kotlin Multiplatform的实现方式,能够在多个平台上共享业务逻辑代码,提高开发效率;③了解Kotlin在不同开发领域的应用场景,为选择合适的技术栈提供参考。; 其他说明:本文不仅提供了理论知识,还结合了大量代码案例,帮助读者更好地理解和实践Kotlin的函数式编程特性和跨平台开发能力。建议读者在学习过程中动手实践代码案例,以加深理解和掌握。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值