Codeforces Round #748 (Div. 3) 题解

A. Elections

  • 题意
    给定数值 a , b , c a,b,c a,b,c,问其中一个数大于其他两个数还需要增加多大。

  • 解题思路
    签到。

  • AC代码

/**
  *@filename:A_Elections
  *@author: pursuit
  *@created: 2021-10-13 22:36
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int t, a, b, c;
void solve(){
    int res1 = max(b, c), res2 = max(a, c), res3 = max(a, b);
    if(a > res1){
        res1 = 0;
    }
    else{
        res1 = res1 - a + 1;
    }
    if(b > res2){
        res2 = 0;
    }
    else{
        res2 = res2 - b + 1;
    }
    if(c > res3){
        res3 = 0;
    }
    else{
        res3 = res3 - c + 1;
    }
    cout << res1 << " " << res2 << " " << res3 << endl;
}
int main(){	
    cin >> t;
    while(t -- ){
        cin >> a >> b >> c;
        solve();
    }
    return 0;
}

B. Make it Divisible by 25

  • 题意
    给定一个数值字符串,每次操作你都可以从中删除一个字符,问至少删除多少字符才可以使得剩余字符串能否整除 25 25 25

  • 解题思路
    能整除 25 25 25的尾部两个数为 00 , 25 , 50 , 75 00,25,50,75 00,25,50,75。所以我们判断需要形成这样的尾部数最少需要删除多少字符即可。

  • AC代码

/**
  *@filename:BBB
  *@author: pursuit
  *@created: 2021-10-13 22:40
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int t;
string s;
void solve(){
    int res = INF;
    string temp = "00";
    int cnt = 0, idx = 0;
    bool flag = false;
    for(int i = s.size() - 1; i >= 0; -- i){
        if(s[i] == temp[idx]){
            ++ idx;
            if(i == 0)flag = true;
            if(idx == temp.size())break;
        }
        else{
            ++ cnt;
        }
    }
    if(!flag && idx == temp.size()){
        res = min(res, cnt);
    }
    temp = "52";
    cnt = idx = 0;
    for(int i = s.size() - 1; i >= 0; -- i){
        if(s[i] == temp[idx]){
            ++ idx;
            if(idx == temp.size())break;
        }
        else{
            ++ cnt;
        }
    }
    if(idx == temp.size()){
        res = min(res, cnt);
    }
    temp = "05";
    cnt = idx = 0;
    for(int i = s.size() - 1; i >= 0; -- i){
        if(s[i] == temp[idx]){
            ++ idx;
            if(idx == temp.size())break;
        }
        else{
            ++ cnt;
        }
    }
    if(idx == temp.size()){
        res = min(res, cnt);
    }
    temp = "57";
    cnt = idx = 0;
    for(int i = s.size() - 1; i >= 0; -- i){
        if(s[i] == temp[idx]){
            ++ idx;
            if(idx == temp.size())break;
        }
        else{
            ++ cnt;
        }
    }
    if(idx == temp.size()){
        res = min(res, cnt);
    }
    cout << res << endl;
}
int main(){	
    cin >> t;
    while(t -- ){
        cin >> s;
        solve();
    }
    return 0;
}

C. Save More Mice

  • 题意
    有一只猫位于 0 0 0处,第 i i i只老鼠位于 x i x_i xi处,每秒猫向右移动一格,同时你可以控制一只老鼠移动一格,当猫到达老鼠的位置则会吃掉老鼠,老鼠到达 n n n处即可逃走,问 n n n秒后你最多可以拯救几只老鼠。

  • 解题思路
    贪心的想肯定是将能救的都救了,所以对位置进行排序,先救离猫远的即可。

  • AC代码

/**
  *@filename:C_Save_More_Mice
  *@author: pursuit
  *@created: 2021-10-13 23:00
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;
const int N = 4e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int t, n, m;
int x[N];
ll res = 0;
void solve(){
    sort(x + 1, x + 1 + m);
    int cnt = n, res = 0;
    for(int i = m; i >= 1; -- i){
        if(cnt > n - x[i]){
            ++ res;
            cnt -= (n - x[i]);
        }
        else{
            break;
        }
    }
    printf("%d\n", res);
}
int main(){	
    scanf("%d", &t);
    while(t -- ){
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= m; ++ i){
            scanf("%d", &x[i]);
        }
        solve();
    }
    return 0;
}

D1. All are Same

  • 题意
    给定 n n n个整数,请你选定一个 k k k使得所有整数通过减 k k k操作变成相同的值,若 k k k可以取无穷大,则输出 − 1 -1 1

  • 解题思路
    既然需要变成相同的值,我们肯定都是想变成所有整数中的最小值,那么我们需要去弥补这 n n n个整数与最小值的差值 d d d,如果可以弥补,说明我们选取的 k k k一定是 d d d的因子。至此,我们只需要求出所有差值的最大公约数则是我们选取的 k k k的最大值了。

  • AC代码

/**
  *@filename:D1_All_are_Same
  *@author: pursuit
  *@created: 2021-10-13 23:11
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int t, n, a[N];
int minn;
bool check(){
    for(int i = 2; i<= n; ++ i){
        if(a[i] != a[1])return false;
    }
    return true;
}
void solve(){
    if(check()){
        puts("-1");
    }
    else{
        int gcd = 0;
        for(int i = 1; i <= n; ++ i){
            gcd = __gcd(gcd, a[i] - minn);
        }
        cout << gcd << endl;
    }
}
int main(){	
    cin >> t;
    while(t -- ){
        cin >> n;
        minn = INF;
        for(int i = 1; i <= n; ++ i){
            cin >> a[i];
            minn = min(minn, a[i]);
        }
        solve();
    }
    return 0;
}

D2. Half of Same

  • 题意
    和D1唯一的区别就是我们需要保证 n n n个整数中有一半的整数可以相同。

  • 解题思路
    会了D1,实际上D2也是一样,只是我们无法确定该选择哪些数。如果相同值的数达到了一半,那么 k k k可以取无穷大。如果没有,那么我们可以先将所有的差值处理出来,则我们的 k k k一定是从这些差值的因子中诞生的。很容易证明因子数量不会超过 1 e 4 1e4 1e4。所以枚举这些因子 d d d,同时枚举一个我们需要变成的数,即前一半小的任何一个数。然后判断之后的数与其差值是否为 d d d的倍数。至此题解。注意处理过程中使用 s e t set set提高效率。

  • AC代码

/**
  *@filename:D2_Half_of_Same
  *@author: pursuit
  *@created: 2021-10-16 16:36
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int t, n, a[N];
void solve(){
    sort(a + 1, a + 1 + n);
    int maxx = 0, cnt = 1;
    for(int i = 2; i <= n; ++ i){
        if(a[i] != a[i - 1]){
            maxx = max(cnt, maxx);
            cnt = 1;
        }
        else ++ cnt;
    }
    maxx = max(maxx, cnt);
    if(maxx * 2 >= n)puts("-1");
    else{
        //存所有因子。
        set<int> v1, v2;
        for(int i = 1; i <= n; ++ i){
            for(int j = i + 1; j <= n; ++ j){
                v1.insert(a[j] - a[i]);
            }
        }
        for(auto x : v1){
            for(int j = 1; j * j <= x; ++ j){
                if(x % j)continue;
                v2.insert(j), v2.insert(x / j);
            }
        }
        int res = 0;
        for(auto x : v2){
            //枚举要变成的数。
            for(int i = 1; i <= n / 2 + 1; ++ i){
                int cnt = 1;
                for(int j = i + 1; j <= n; ++ j){
                    if((a[j] - a[i]) % x == 0)++ cnt;
                }
                if(cnt * 2 >= n){
                    res = x;
                }
            }
        }
        cout << res << endl;
    }
}
int main(){	
    cin >> t;
    while(t -- ){
        cin >> n;
        for(int i = 1; i <= n; ++ i){
            cin >> a[i];
        }
        solve();
    }
    return 0;
}

E. Gardener and Tree

  • 题意
    给定一颗树,每次操作都可以将叶子结点全部删掉,问 k k k次操作之后,树还剩下几个结点。

  • 解题思路
    度为 1 1 1的点则是叶子结点,我们首先需要将所有结点的度处理出来,然后从这些点出发跑bfs,模拟删点过程(即其相邻点的度减 1 1 1),然后同样将度为 1 1 1的叶子结点放入,注意我们需要存储当前是进行第几次操作,这样可以在完成 k k k次操作之后退出。
    注意特判 n = 1 n=1 n=1的时候,此时没有边,由于 k ≥ 1 k\geq1 k1,所以答案为 0 0 0

  • AC代码

/**
  *@filename:E_Gardener_and_Tree
  *@author: pursuit
  *@created: 2021-10-13 23:21
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;
const int N = 4e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int t, n, k, tot;
bool vis[N];
struct Edge{
    int to, next;
}edges[N << 1];
struct node{
    int u, cnt;
};
int head[N], du[N];
void add(int u, int v){
    edges[++ tot].to = v;
    edges[tot].next = head[u];
    head[u] = tot;
}
void init(){
    for(int i = 1; i <= n; ++ i)head[i] = du[i] = 0;
    tot = 0;
}
void solve(){
    if(n == 1){
        puts("0");
        return;
    }
    queue<node> q;
    int res = n;
    for(int i = 1; i <= n; ++ i){
        if(du[i] == 1){
            -- du[i];
            q.push({i, 1});
            -- res;
        }
    }
    while(!q.empty()){
        node temp = q.front();
        if(temp.cnt == k || res == 0)break;
        q.pop();
        for(int i = head[temp.u]; i; i = edges[i].next){
            int v = edges[i].to;
            -- du[v];
            if(du[v] == 1)q.push({v, temp.cnt + 1}), -- res;
        }
    }
    printf("%d\n", res);
    init();
}
int main(){
    scanf("%d", &t);
    while(t -- ){
        scanf("%d%d", &n, &k);
        tot = 0;
        for(int i = 1, u, v; i < n; ++ i){
            scanf("%d%d", &u, &v);
            add(u, v), add(v, u);
            ++ du[u], ++ du[v];
        }
        solve();
    }
    return 0;
}

F. Red-Black Number

  • 题意
    给你一个字符串 s s s,你需要对其中字符进行染色,红色的字符连在一起组成一个字符串数值为 A A A,黑色的字符连在一起组成一个字符串数值为 B B B,需要满足 A A A能整除 a a a B B B能整除 b b b。问其中 A A A B B B位数相差最小值为多少。

  • 解题思路
    即对于字符串中的字符我们是染成红色还是染成黑色,这样乍一看我们有 2 n 2^n 2n种选择。可我们又注意到 a a a b ≤ 40 b\leq 40 b40,所以取余有 40 40 40种可能,而 n ≤ 40 n\leq 40 n40,我们可以用 d p [ u ] [ m a ] [ m b ] [ c n t a ] dp[u][ma][mb][cnta] dp[u][ma][mb][cnta]表示考虑第 u u u位且当前选取数 A A A a a a m a ma ma,当前选取数 B B B b b b m b mb mb,且 A A A c n t a cnta cnta位的状态是否被访问过。那么状态数量为 4 0 4 = 2.56 × 1 0 6 40^4=2.56\times 10^6 404=2.56×106,故我们可以 d f s dfs dfs模拟选取,加上记忆化搜索即可通过。

  • AC代码

/**
  *@filename:F_Red_Black_Number
  *@author: pursuit
  *@created: 2021-10-16 15:58
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;
const int N = 50 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;

bool dp[N][N][N][N];//dp[u][ma][mb][cnta]表示考虑第u位且当前选取数A模a为ma,当前选取数B模b为mb,且A为cnta位的状态是否被访问过.
int t, n, a, b, res;
bool vis[N], ok[N];//vis[i]表示第i个数是否被A选取。
string s;
void dfs(int u, int ma, int mb, int cnta){
    if(u == n){
        if(!ma && !mb && cnta && cnta < n){
            if(abs(n - 2 * cnta) < res){
                res = abs(n - 2 * cnta);
                for(int i = 0; i < n; ++ i)ok[i] = vis[i];
            }
        }
        return;
    }
    if(dp[u][ma][mb][cnta])return;
    dp[u][ma][mb][cnta] = true;
    vis[u] = false;
    dfs(u + 1, ma, (mb * 10 + s[u] - '0') % b, cnta);
    vis[u] = true;
    dfs(u + 1, (ma * 10 + s[u] - '0') % a, mb, cnta + 1);
}
void solve(){
    dfs(0, 0, 0, 0);
    if(res == 1e9){
        puts("-1");
        return;
    }
    for(int i = 0; i < n; ++ i){
        if(ok[i])printf("R");
        else printf("B");
    }
    puts("");
}
int main(){	
    cin >> t;
    while(t -- ){
        cin >> n >> a >> b;
        cin >> s;
        res = 1e9;
        memset(dp, false, sizeof(dp));
        solve();
    }
    return 0;
}

G. Changing Brackets

  • 题意
    给你一个包含[,],(,)的字符串序列,你可以进行两种操作,第一种操作是将()转换,[]相互转换,这种操作不需要花费,另一种操作是将[变成(]变成。先有q次查询,每次查询给定[l,r],问 s l . . s r s_l..s_r sl..sr这一段字符串序列变成合法括号序列的最小花费。

  • 解题思路
    我们发现,如果对于只有()括号的序列,那么是不用任何花费的。关键在于处理[],我们肯定是尽可能不进行操作 2 2 2。我们发现,奇数位置上的中括号和偶数位置上的中括号进行组合且合法,因为中间都是小括号,而这两个中括号可以通过操作 1 1 1匹配。所以我们可以用前缀和处理表示 s u m [ i ] sum[i] sum[i] i i i个字符串序列还有多少中括号没有配对,那么答案自然为 a b s ( s u m [ r ] − s u m [ l − 1 ] ) abs(sum[r]-sum[l-1]) abs(sum[r]sum[l1]),加上绝对值是因为万一偶数位置比奇数位置多这种情况。理解抵消这个操作这道题即可解。

  • AC代码

/**
  *@filename:G_Changing_Brackets
  *@author: pursuit
  *@created: 2021-10-16 17:21
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e6 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;

int t, q, sum[N], l, r;
string s;
void solve(){
    cin >> l >> r;
    cout << abs(sum[r] - sum[l - 1]) << endl;
}
int main(){	
    cin >> t;
    while(t -- ){
        cin >> s >> q;
        for(int i = 0; i < s.size(); ++ i){
            sum[i + 1] = sum[i];
            if(s[i] == '[' || s[i] == ']'){
                if(i % 2)++ sum[i + 1];
                else -- sum[i + 1];
            }
        }
        while(q -- ){
            solve();
        }
    }
    return 0;
}
posted @ 2022-03-26 16:47  unique_pursuit  阅读(60)  评论(0)    收藏  举报