Codeforces Round #786 (Div. 3)题解A~F

Codeforces Round #786 (Div. 3)

A. Number Transformation

原题:

请添加图片描述

题目大意:

给你一个x,y,问你能否对x通过乘以a次b可以得到y的方案,可以输出a和b即可(答案不唯一),如果不可以,输出0 0。

思路分析:

代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int t, a, b, x, y;
int main()
{
    cin >> t;
    while(t --){
        cin >> x >> y;
        if(y % x){
            cout<<"0 0"<<'\n';
        }
        else{
            cout<<"1 "<<y / x << "\n";
        }
    }
    return 0;
}

B. Dictionary

原题:

请添加图片描述
请添加图片描述

题目大意:

根据题意对给定的字符串输出其对应的下标即可。

思路分析:

代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int t;
string tmp;
int main()
{
    cin >> t;
    while(t -- ){
        cin>>tmp;
        int ans = 0;
        ans = (tmp[0] - 'a') * 25;
        if(tmp[1] > tmp[0])ans += tmp[1] - 'a';
        else ans += tmp[1] - 'a' + 1;
        cout << ans << '\n';
    }
    return 0;
}

C. Infinite Replacement

原题:

请添加图片描述

请添加图片描述

题目大意:

给定一个字符串s和字符串t,字符串都是由a字符构成,我们通过t取替换s中字符a的地方,能够得到多少方案。如果会无限循环输出-1,反之输出方案即可。

思路分析:

分类讨论:

1)如果t = ‘a’; 那么就一种方案 1
2)如果t 中有’a’, 每次替换s的时候都会多一个a,会无限循环,那么就 - 1
3)如果t 中没有a, 就是每次替换s的方案数,即 2^len

代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int q;
string s, t;
long long jc(int n){
    long long ans = 1;
    for(int i = 1; i <= n; i ++)ans *= 2;
    return ans;
}
int main()
{
    cin >> q;
    while(q --){
        cin >> s;
        cin >> t;
        int flag = 0, len = t.size(), len2 = s.size();
        for(int i = 0; i < len; i ++){
            if(t[i] == 'a'){
                flag = 1;
                break;
            }
        }
        if(t.size() == 1 && flag)cout<<"1"<<'\n';
        else if(flag)cout<<"-1"<<'\n';
        else {
            long long ans = jc(len2);
            cout << ans<< '\n';
        }
    }
    return 0;
}
/*
1)如果t = a; 那么就一种方案 1
2)如果t 中有a, 那么就 - 1
3)如果t 中没有a, 那么就 2^len
*/

D. A-B-C Sort

原题:

请添加图片描述
请添加图片描述

题目大意:

先后对a数组和b数组进行操作,问能否使得得到的c是非递减的。

操作:

请添加图片描述

思路分析:

对a数组考虑,可以发现,最前面的数肯定是先被c取到放到最后面的数

如果要让最后的c数组是非递减的,必须满足:

如果初始a数组的长度n是偶数:t == 2;

如果初始a数组的长度n是奇数:t == 1;

1)t == 1时,下标idx数的大小要小于等于idx + 2和idx + 3

  1. t == 2时,下标idx数的大小要小于等于idx + 1和idx + 2
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e6 + 5;
int t, n;
int a[N];
int main()
{
    cin >> t;
    while(t --){
        cin >> n;
        for(int i = 1; i <= n; i ++)cin >> a[i];
        int flag = 1, t = 1;
        if(n % 2)t = 2;
        for(int idx = 1; idx <= n; idx ++){
            if(t == 1){
                t = 2;
                if(a[idx] > a[idx + 2] && idx + 2 <= n){
                    flag = 0;
                    break;
                }
                if(a[idx] > a[idx + 3] && idx + 3 <= n){
                    flag = 0;
                    break;
                }
            }
            else if(t == 2){
                t = 1;
                if(a[idx] > a[idx + 1] && idx + 1 <= n){
                    flag = 0;
                    break;
                }
                if(a[idx] > a[idx + 2] && idx + 2 <= n){
                    flag = 0;
                    break;
                }
            }
        }
        if(flag)cout << "YES" << '\n';
        else cout << "NO" << '\n';
        
    }
    return 0;
}

E. Breaking the Wall

原题:

请添加图片描述
请添加图片描述
请添加图片描述

题目大意:

有n面墙,问你摧毁任意两座(可以不相连)需要的最少操作数。

每一次操作:可以选择任意一座墙造成2点伤害,并且其左右相邻的墙同时收到1点伤害。

思路分析:

分类讨论一下:

1)攻击使相邻两个使两个摧毁:

​ 最优:令两个墙中强度最小为minn,最大为maxx

再次讨论:

1、如果minn * 2 <= maxx

​ 我们直接可以通过用2伤害攻击强大最大的墙,当最大的墙摧毁时,那么较小的那面墙也肯定摧毁了。

2、如果minn * 2 > maxx

​ 用2伤害直接攻击最大强度的墙,肯定会达到两面墙强度相等的时候,然后依次轮流每次攻击一面墙,两面墙的差最多为1,让输出达到最大化,结果肯定能够同时到达0 或者 一个为0 一个为 1,后者就直接再攻击依次就好了。

for(int i = 1; i <= n - 1; i ++){
        int maxx = -N, minn = N;
        maxx = max(a[i], a[i + 1]);
        minn = min(a[i], a[i + 1]);
        if(minn * 2 <= maxx){
            s1 = min(s1, (maxx + 1) / 2);
        }
        else{
            s1 = min(s1, (a[i] + a[i + 1] + 2) / 3);
        }
    }

2)通过攻击中间一个摧毁其旁边两面墙:

最优:枚举所有情况,攻击中间一个墙,如果左右两边有一面墙强度为0了,就直接用2伤害去攻击另一边的墙, 取最小值。

for(int i = 1; i <= n - 2; i ++){
        int tmp = min(a[i], a[i + 2]) + (abs(a[i + 2] - a[i]) + 1) / 2;
        s2 = min(s2, tmp);
    }

3)直接攻击摧毁两个不相邻的墙

​ 最优情况就是找两个强度最小min1和min2的墙,让后分别通过两点伤害就他们摧毁即可。

(min1 + 1) / 2 + (min2 + 1) / 2

因为1) 2) 3 )就包含了所有情况,所以答案即取1) 2) 3)的最小值

代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e6 + 10;
int n, s1 = N, s2 = N, ans = N;
int a[N];
int main()
{
    cin >> n;
    for(int i = 1; i <= n; i ++)cin >> a[i];

    for(int i = 1; i <= n - 1; i ++){
        int maxx = -N, minn = N;
        maxx = max(a[i], a[i + 1]);
        minn = min(a[i], a[i + 1]);
        if(minn * 2 <= maxx){
            s1 = min(s1, (maxx + 1) / 2);
        }
        else{
            s1 = min(s1, (a[i] + a[i + 1] + 2) / 3);
        }
    }

    for(int i = 1; i <= n - 2; i ++){
        int tmp = min(a[i], a[i + 2]) + (abs(a[i + 2] - a[i]) + 1) / 2;
        s2 = min(s2, tmp);
    }

    sort(a + 1, a + n + 1);
    ans = min({s1, s2, (a[1] + 1) / 2 + (a[2] + 1) / 2});

    cout << ans << '\n';

    return 0;
}

F. Desktop Rearrangement

原题:

请添加图片描述
请添加图片描述

题目大意:

加删图标,问排列整齐最少需要几步。

整齐:从左往右依次排数列,排满一列排下列。

思路分析:

分类讨论,维护不需要排的数量,答案就是总图标数减去不需要排的图标数。

代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;
typedef pair<int, int> PII;
const int N = 1e3 + 5, M = 1e6 + 5;
int n, m, q, sum = 0;
char g[N][N];
map<PII, int>mp;
int main()
{
    cin >> n >> m >> q;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j ++){
            cin >> g[i][j];
            if(g[i][j] == '*'){
                sum ++;
                mp[{i, j}] = 1;
            }
        }
    }
    //统计在范围内的点数
    int cnt = 0;
    for(int i = 1; i <= n; i ++){
        for(int j = 1; j <= m; j ++){
            if(mp[{i, j}] == 1 && (j - 1) * n + i <= sum)cnt ++;
        }
    }

    //最大能排到的位置ii jj
    int ii, jj;
    if(sum % n == 0){
        ii = n;
        jj = sum / n;
    }
    else {
        ii = sum % n;
        jj = sum / n + 1;
    }

    //cout<<sum<<" "<<cnt<<'\n';

    while(q --){
        int x, y, tmp, ans;
        cin >> x >> y;
        tmp = n * (y - 1) + x;
        // cout<<"tmp:"<<tmp<<" " << "sum:"<<sum<<" "<<"cnt:"<<cnt<<'\n';
        // cout<<"mp:"<<mp[{x, y}]<<'\n';
        
        if(tmp > sum && mp[{x, y}] == 1){
            sum --;
            mp[{x, y}] = 0;
            if(mp[{ii, jj}] == 1)cnt --;
            if(ii == 1){
                ii = n;
                jj --;
            }
            else{
                ii --;
            }
            
        }
        else if(tmp <= sum && mp[{x, y}] == 1){
            sum --;
            cnt --; 
            mp[{x, y}] = 0;
            
            if(mp[{ii, jj}] == 1 && (x != ii || y != jj))cnt --;

            if(ii == 1){
                ii = n;
                jj --;
            }
            else{
                ii --;
            }
           
        }
        else if(tmp <= sum && mp[{x, y}] == 0){
            cnt ++; sum ++;mp[{x, y}] = 1;
            if (ii == n){
                ii = 1;
                jj += 1;
            }
            else {
                ii ++;
            }
            if(mp[{ii, jj}] == 1 )cnt++;
            
        }
        else if(tmp > sum && mp[{x, y}] == 0){
            sum ++;mp[{x, y}] = 1;
            if (ii == n){
                ii = 1;
                jj += 1;
            }
            else {
                ii ++;
            }
            if(mp[{ii, jj}] == 1 )cnt++;
            
        }
        ans = sum - cnt;
        cout << ans << '\n';
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值