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

178 阅读1分钟

A. Number Transformation

题意:有 T 组数据,给定 xxyy,是否存在 xba=yx*b^a = y, 存在输出 aabb, 否则输出 0 0。

#include <iostream>
using namespace std;
 
int main(){
    int t;
    cin>>t;
    while(t--){
       int x, y;
       cin>>x>>y;
       if(y%x != 0){
           cout<<0<<" "<<0<<endl;
       }else{
           int t = y/x;
           cout<<1<<" "<<t<<endl;
       }
    }
    return 0;
}

B. Dictionary

题意: 2个字母的字典升序, 从 1 开始, 输入2个字母, 找出在字典的位置。 注意去掉相同字母。

#include <iostream>
using namespace std;

int main(){
    int t;
    cin>>t;
    while(t--){
        string s;
        cin>>s;
        int res = (s[0]-'a')*26+(s[1]-'a');
        res -= s[0] -'a';
        if(s[1] > s[0]){
            res --;
        }
        cout<<res+1<<endl;
    }
    return 0;
}

C. Infinite Replacement

题意:给一个字符串ss 和字符串 ttss中的字符 a 可以替换成 t 或者不替换,问有多少种替换方式,如果是无限多个返回-1。

分情况讨论:

  1. t 的长度为 1,并且字符为 a, 返回 1。
  2. t 的长度大于 1,并且 t 中包含字符 a, 可以组成无限长,返回 -1。
  3. 判断 s 串中字符 a 的个数, pow(2, count(a))。 注意开 long long。
#include <iostream>
using namespace std;

int main(){
    int t;
    cin>>t;
    while(t--){
        string a, b;
        cin>>a>>b;
        if(b.find('a') != string::npos){
            if(b.size() == 1){
                cout<<1<<endl;
            }else cout<<-1<<endl;
        }else{
           int cnt = 0;
           for(auto& c : a){
               if(c == 'a') cnt++;
           }
           long long res = 1;
           for(int i=1; i<=cnt; i++){
               res *=2;
           }
           cout<<res<<endl;
        }
    }
    return 0;
}

D. A-B-C Sort

题意:有 3个数组, a, b, c, a 有 n个元素, b, c是空的。
有以下2个步骤:

  1. a 不为空时,将追后一个元素移动到 b 数组的中间,如果 b 数组的长度为奇数,可以放到中的左边或者中的右边。
  2. 当 b 不为空时,将 b 中间的元素移动到 c 数组的后面,如果 b 数组的长度为偶数时,中间的2个值随便取一个。 判断 c 数组是否可以为升序的数组?
    通过模拟数据,只需要 a 数组中的长度2 数值交换,可以组成升序,那么 c 就可以组成升序。
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 2e5+10;

int a[N], b[N];
int main(){
    int t;
    cin>>t;
    while(t--){
       int n;
       cin>>n;
       for(int i=0; i<n; i++) cin>>a[i], b[i] = a[i];
       for(int i=n-1; i>0; i-=2){
           if(a[i] < a[i-1]){
               swap(a[i], a[i-1]);
           }
       }
       sort(b, b+n);
       bool flag = true;
       for(int i=0; i<n; i++){
           if(a[i] != b[i]){
               cout<<"NO"<<endl;
               flag = false;
               break;
           }
       }
       if(flag) cout<<"YES"<<endl;
    }
    return 0;
}

E. Breaking the Wall

题意: 用炮弹去炸墙,墙是是一个大小为 n 的数组组成, 每一个数值代表的这墙的生命值,如果生命值小于等于 0 ,这一块就穿了, 攻击城堡需要两处生命值为 0, 一个炮弹打到 x 处,x 出的生命值 -2, x+1x1x+1 和 x-1 处的生命值减 -1,问需用最少多少个炮弹炸出两个坑。
分情况讨论:

  1. 找 2 处最小的值的地方炸就完事, min1/2\lceil min1/2 \rceil + min2/2\lceil min2/2 \rceil
  2. 找 2 处相邻的地方炸
    • 第一种 a[i]>=a[i+1]2a[i] >= a[i+1]*2 a[i]/2\lceil a[i]/2 \rceil
    • 第二种 a[i]<a[i+1]2a[i] < a[i+1]*2 , 轰炸一次, 相当于 iii+1i+1 整体 3-3,所以 (a[i]+a[i+1])/3\lceil (a[i]+a[i+1])/3 \rceil
  3. i1i-1i+1i+1, 炸 ii 处, 如果 i1i-1i+1i+1 为 奇数,则选择花费一次操作令它们都减少 11(a[i1]+a[i+1])/2(a[i-1]+a[i+1])/2
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;

const int N = 2e5+10;

int a[N];
int main(){
    int n;
    cin>>n;
    for(int i=0; i<n; i++) cin>>a[i];
    int min1 = 1e6+5, min2 = 1e6+5;
    // 找最小值和次小值
    for(int i=0; i<n; i++){
        if(min1 >= a[i]){
            if(min1 <= min2) min2 = min1;
            min1 = a[i];
        }else{
            if(a[i] <= min2) min2 = a[i];
        }
    }
    // 不相邻最小2个点
    int minv = (min1+1)/2+(min2+1)/2;
    // 相邻的 2个点
    for(int i=0; i<n-1; i++){
        int t1 = a[i], t2 = a[i+1];
        if(t1 < t2) swap(t1, t2);
        if(t1 >= 2*t2) {
            minv = min(minv, (t1+1)/2);
        }else{
            minv = min(minv, (int)ceil((t1+t2)/3.0));
        }
    }
    // a[i-1] && a[i+1]
    for(int i=1; i<n-1; i++){
        int t1 = a[i-1], t2 = a[i+1];
        if(t1%2 && t2%2){
            minv = min(minv, (t1+t2)/2);
        }
    }
    cout<<minv<<endl;
    return 0;
}

F. Desktop Rearrangement

题意:给一个 nmn*m 的二维数组, '*' 和 '.' 组成,如果 '*' 都是按列全部填充,或者第一列填满,到下一列,都认为是 good,* 可以任意移动位置,算作一次。 给 q 个询问, xx, yy 为坐标,如果 xx, yy  处为 *, 改为‘.’,如果 xxyy 处为'.', 将改成 *, 等需要移动多少个'*'。
统计所有的 * 的个数 cnt, 统计每一列的 * 的 个数 cols, 将对应 xx, yy 位置进行改变, 统计在 cnt/ncnt/ ncnt%rcnt\%r 行, * 的个数 sumsum, cntsumcnt - sum 就是在这个区间之外的 *, 也就是需要移动的个数。

image.png

#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1005;

char g[N][N];
int col[N];
int main(){
    int n, m, q, cnt = 0;
    cin>>n>>m>>q;
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++){ 
            cin>>g[i][j];
            if(g[i][j] == '*'){
                cnt++;
                col[j]++;
            }
        }
    while(q--){
        int x, y;
        cin>>x>>y;
        x--; y--;
        if(g[x][y] == '*'){
            g[x][y] = '.';
            cnt--;
            col[y]--;
        }else g[x][y] = '*', cnt++, col[y]++;
        int sum = 0;
        int a = cnt/n, b = cnt%n;
        for(int i=0; i<a; i++){
            sum += col[i];
        }
        for(int i=0; i<b; i++){
            if(g[i][a] == '*') sum++;
        }
        cout<<cnt - sum<<endl;
    }
    return 0;
}