Codeforces Round #738 (Div. 2)

本文介绍了Codeforces Round #738 (Div.2) 中的四道编程题目,涉及位运算优化、字符串处理和图论策略。题目包括按位与的最大值问题、字符串相邻字符相同数量最小化、森林遍历路径和加边策略,每道题均给出了详细的思路解析和C++代码实现。
摘要由CSDN通过智能技术生成
Codeforces Round #738 (Div. 2)

A Mocha and Math

题目

给定一个长度为 n n n 的数列 a a a,每次可以选择一个区间 [ l , r ] [l,r] [l,r],对于 0 ≤ i ≤ r − l 0\le i\le r-l 0irl,将 a l + i a_{l+i} al+i 变为 a l + i   and ⁡   a r − i a_{l+i}\ \operatorname{and}\ a_{r-i} al+i and ari。其中 and ⁡ \operatorname{and} and 表示按位与。

你可以进行无限多次操作,问最终序列中最大值最小是多少。

思路

按为与的结果是不会增的,所以我们能操作就操作,根据题目意思,每两个数之间都可以进行按位与操作,因此,答案就是所有数按为与的结果.

代码

#include <iostream>
#include <cstdio>
using namespace std;
int read() {
    int re = 0;
    char c = getchar();
    bool negt = false;
    while(c < '0' || c > '9')
        negt |= (c == '-')  , c = getchar();
    while(c >= '0' && c <= '9')
        re = (re << 1) + (re << 3) + c - '0' , c = getchar();
    return negt ? -re : re;
}
template <char l , char r>
char readc() {
    char c = getchar();
    while(c < l || c > r)c = getchar();
    return c;
}

const int N = 110;
int a[N];
int n;
int ans = 0;
void solve() {
    n = read();
    ans = (unsigned)(-1);
    for(int i = 1 ; i <= n ; i++)
        ans &= read();
    cout << ans << endl;
}
int main() {
    int T = read();
    while(T--)solve();
    return 0;
}

B B Mocha and Red and Blue

题目

给定长为 n n n 的仅由 R \texttt{R} R B \texttt{B} B ? \texttt{?} ? 组成的字符串 S S S,请你在 ? \texttt{?} ? 处填入 R \texttt{R} R B \texttt{B} B,使得相邻位置字符相同的数量最少。

思路

本来还在想奇奇怪怪的DP,然后发现贪心就好.

对于每个位置 i ∈ [ 2 , n ] i\in[2,n] i[2,n],如果前面是B我们就放R,前面是R,我们就放B.这样每个位置最多只可能和右边冲突.

对于第一个位置,如果是?,我们找到从左向右第一个不是?的位置,和那个位置错开即可.

代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int read() {
    int re = 0;
    char c = getchar();
    bool negt = false;
    while(c < '0' || c > '9')
        negt |= (c == '-')  , c = getchar();
    while(c >= '0' && c <= '9')
        re = (re << 1) + (re << 3) + c - '0' , c = getchar();
    return negt ? -re : re;
}

char readc() {
    char c = getchar();
    while(c != 'R' && c != 'G' && c != 'B' && c != '?')c = getchar();
    return c;
}

const int N = 110;
char s[N];
int n;
int f[N][5];

const char col[] = "RB";
void solve() {
    memset(s , 0 , sizeof(s));
    n =read();
    int pos = 0;
    for(int i = 1 ; i <= n ; i++) {
        // char c = readc();
        s[i] = readc();
        if(pos == 0 && s[i] != '?')pos = i;
    }
    if(pos != 0 && s[1] == '?')s[1] = "BR"[(pos % 2 + (s[pos] == 'B') ) % 2];
    for(int i = 1 ; i <= n ; i++)
        if(s[i] == '?') {
            s[i] = s[i - 1] == 'B' ? 'R' : 'B';
        }
    puts(s + 1);
}
int main() {
    int T = read();
    while(T--)solve();
    return 0;
}

C Mocha and Hiking

题目

给定一张 n n n 个点 2 n − 1 2n-1 2n1 条边的图,其中边分两种:

  • 对于所有 1 ≤ i ≤ n 1\le i\le n 1in,存在一条由节点 i i i 连向节点 i + 1 i+1 i+1 的边;
  • 对于所有 1 ≤ i ≤ n 1\le i\le n 1in,存在一条由节点 i i i 连向节点 n + 1 n+1 n+1 的边或者一条由节点 n + 1 n+1 n+1 连向节点 i i i 的边。

请你输出一种从任意一个点开始遍历所有点的方案,若无法遍历则输出 − 1 -1 1

思路

由题目我们可以看到,总体趋势是向右走的,且需要额外考虑的是 n + 1 n+1 n+1号点.

  1. 如果 a 1 = 1 a_1=1 a1=1,走以下路径: n + 1 → 1 → 2 → ⋯ → n n+1\to1\to2\to\cdots\to n n+112n.
  2. 如果 a n = 0 a_n=0 an=0,走以下路径: 1 → 2 → 3 → 4 → ⋯ → n → n + 1 1\to2\to3\to4\to\cdots\to n\to n+1 1234nn+1.
  3. 如果存在一个 i i i, a i = 0 , a i + 1 = 1 a_i=0,a_{i+1}=1 ai=0,ai+1=1走以下路径: 1 → 2 → 3 → ⋯ → i → n + 1 → i + 1 → i + 2 → ⋯ → n 1\to2\to3\to\cdots\to i\to n+1\to i+1\to i+2\to\cdots\to n 123in+1i+1i+2n.

以上包含了所有有解的情况.

代码

#include <iostream>
#include <cstdio>
using namespace std;
int read() {
    int re = 0;
    char c = getchar();
    bool negt = false;
    while(c < '0' || c > '9')
        negt |= (c == '-')  , c = getchar();
    while(c >= '0' && c <= '9')
        re = (re << 1) + (re << 3) + c - '0' , c = getchar();
    return negt ? -re : re;
}
template <char l , char r>
char readc() {
    char c = getchar();
    while(c < l || c > r)c = getchar();
    return c;
}

const int N = 1e4 + 10;
int a[N];
void solve() {
    int n;
    n = read();
    for(int i = 1 ; i <= n ; i++)a[i] = read();
    for(int i = 1 ; i < n ; i++) {
        if(a[i] == 0 && a[i + 1] == 1) {
            for(int j = 1 ; j <= i ; j++)
                printf("%d " , j);
            printf ("%d " , n + 1);
            for(int j = i + 1 ; j <= n ; j++)
                printf("%d " , j);
            putchar('\n');
            return ;
        }
    }
    if(a[1] == 1) {
        printf("%d " , n + 1);
        for(int i = 1 ; i <= n ; i++)
            printf ("%d " , i);
        putchar('\n');
        return ;
    }
    if(a[n] == 0) {
        for(int i = 1 ; i <= n + 1 ; i++)
            printf("%d " , i);
        putchar('\n');
        return ;
    }
    puts("-1");
}
int main() {
    int T = read();
    while(T--)solve();
    return 0;
}

D1&D2 Mocha and Diana

题目

给你两棵森林,节点数均为 n n n

允许你进行加边操作,但是有两个要求:

  • 如果在第一个森林加一条 ( u , v ) (u,v) (u,v) 的边,第二个森林也要进行同样的操作。反之同理。
  • 加边后两个森林依旧是森林。(一棵树也是森林)

求最多能加几条边,并输出加边方案。

思路

对于D1,枚举两个点 u , v u,v u,v能连就连,连玩合并并查集即可,时间复杂度为 O ( n 2 ) O(n^2) O(n2).

对于D2,我们分两步:

  1. 从枚举一个点 u u u, 1 , u 1,u 1,u两个点能连就连,连玩放入一个并查集.这样我们在两个森林中分别得到两个大连通块,为了方便,成为连通块A,和连通块B.
  2. 枚举连通块A外的一个点 u u u,和连通块B外的一个点 v v v. u , v u,v u,v是一定可以连边的.
    简单证明就是 u u u一定在连通块B中(如果不在,第一步就会将 u , v u,v u,v连起来), v v v也一定在连通块A中(同理).
    因此, u , v u,v u,v满足连边条件.所以将 u , v u,v u,v连边,然后它们就都同时在A,B连通块内了,(所以一个点只能用一次).我们求出所有不在A连通块内的点的集合,和所有不在B连通块内的点的集合,两个集合内的点互相连边即可(可以证明两个集合的交集为空).

代码

#include <iostream>
#include <cstdio>
#include <vector>
#include <map>
using namespace std;
int read() {
    int re = 0;
    char c = getchar();
    bool negt = false;
    while(c < '0' || c > '9')
        negt |= (c == '-')  , c = getchar();
    while(c >= '0' && c <= '9')
        re = (re << 1) + (re << 3) + c - '0' , c = getchar();
    return negt ? -re : re;
}
template <char l , char r>
char readc() {
    char c = getchar();
    while(c < l || c > r)c = getchar();
    return c;
}

const int N = 1e5 + 10;
int n;
int m1 , m2;

vector <pair<int , int> > ans;

struct DSU {
    int fa[N];
    DSU() {
        for(int i = 0 ; i < N ; i++)fa[i] = i;
    }
    int findroot(int x) {
        return fa[x] == x ? x : (fa[x] = findroot(fa[x]));
    }
    void merge(int u , int v) {
        u = findroot(u) , v = findroot(v);
        if(u != v)
            fa[u] = v;
    }
} d1 , d2;
int main() {
    n = read() , m1 = read() , m2 = read();
    for(int i = 1 ; i <= m1 ; i++) {
        int u = read() , v = read();
        d1.merge(u , v);
    }
    for(int i = 1 ; i <= m2 ; i++) {
        int u = read() , v = read();
        d2.merge(u , v);
    }

    for(int i = 2 ; i <= n ; i++) {
        if(d1.findroot(1) != d1.findroot(i) && d2.findroot(1) != d2.findroot(i)) {
            d1.merge(1 , i) , d2.merge(1 , i);
            ans.push_back(make_pair(1 , i));
        }
    }
    vector <int> a , b;
    for(int i = 1 ; i <= n ; i++) {
        if(d1.findroot(1) != d1.findroot(i))a.push_back(i) , d1.merge(1 , i);
        else if(d2.findroot(1) != d2.findroot(i))b.push_back(i) , d2.merge(1 , i);
    }
    for(int i = 0 ; i < a.size() && i < b.size() ; i++)
        ans.push_back(make_pair(a[i] , b[i]));


    printf("%d\n" , ans.size());
    for(auto i : ans) {
        printf("%d %d\n" , i.first , i.second);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
4S店客户管理小程序-毕业设计,基于微信小程序+SSM+MySql开发,源码+数据库+论文答辩+毕业论文+视频演示 社会的发展和科学技术的进步,互联网技术越来越受欢迎。手机也逐渐受到广大人民群众的喜爱,也逐渐进入了每个用户的使用。手机具有便利性,速度快,效率高,成本低等优点。 因此,构建符合自己要的操作系统是非常有意义的。 本文从管理员、用户的功能要出发,4S店客户管理系统中的功能模块主要是实现管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理,用户客户端:首页、车展、新闻头条、我的。门店客户端:首页、车展、新闻头条、我的经过认真细致的研究,精心准备和规划,最后测试成功,系统可以正常使用。分析功能调整与4S店客户管理系统实现的实际需相结合,讨论了微信开发者技术与后台结合java语言和MySQL数据库开发4S店客户管理系统的使用。 关键字:4S店客户管理系统小程序 微信开发者 Java技术 MySQL数据库 软件的功能: 1、开发实现4S店客户管理系统的整个系统程序; 2、管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理等。 3、用户客户端:首页、车展、新闻头条、我的 4、门店客户端:首页、车展、新闻头条、我的等相应操作; 5、基础数据管理:实现系统基本信息的添加、修改及删除等操作,并且根据需进行交流信息的查看及回复相应操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值