Codeforces Round #738 (Div. 2)

Codeforces Round #738 (Div. 2)

A Mocha and Math

题目

给定一个长度为 \(n\) 的数列 \(a\),每次可以选择一个区间 \([l,r]\),对于 \(0\le i\le r-l\),将 \(a_{l+i}\) 变为 \(a_{l+i}\ \operatorname{and}\ a_{r-i}\)。其中 \(\operatorname{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\) 的仅由 \(\texttt{R}\)\(\texttt{B}\)\(\texttt{?}\) 组成的字符串 \(S\),请你在 \(\texttt{?}\) 处填入 \(\texttt{R}\)\(\texttt{B}\),使得相邻位置字符相同的数量最少。

思路

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

对于每个位置\(i\in[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\) 个点 \(2n-1\) 条边的图,其中边分两种:

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

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

思路

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

  1. 如果\(a_1=1\),走以下路径:\(n+1\to1\to2\to\cdots\to n\).
  2. 如果\(a_n=0\),走以下路径:\(1\to2\to3\to4\to\cdots\to n\to n+1\).
  3. 如果存在一个\(i\),\(a_i=0,a_{i+1}=1\)走以下路径:\(1\to2\to3\to\cdots\to i\to n+1\to i+1\to i+2\to\cdots\to n\).

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

代码

#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\)

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

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

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

思路

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

对于D2,我们分两步:

  1. 从枚举一个点\(u\),\(1,u\)两个点能连就连,连玩放入一个并查集.这样我们在两个森林中分别得到两个大连通块,为了方便,成为连通块A,和连通块B.
  2. 枚举连通块A外的一个点\(u\),和连通块B外的一个点\(v\).\(u,v\)是一定可以连边的.
    简单证明就是\(u\)一定在连通块B中(如果不在,第一步就会将\(u,v\)连起来),\(v\)也一定在连通块A中(同理).
    因此,\(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;
}
posted @ 2021-11-12 08:15  追梦人1024  阅读(24)  评论(0编辑  收藏  举报