Codeforces Round #788 (Div. 2) 题解 (A-D)

153 阅读1分钟

A. Prof. Slim

题意 : 有一个 a 数组,在 1<=i,j<=n1<=i, j<= n 之间, 将 iijj 数值的符号交换,可以使得数组 a 是否为非降序的数组。
从左往右找大于 0 的位置和从右往左找 小于 0 的位置,进行符号交换,最后判断数组 a 是否非降序。

#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <queue>

using namespace std;

const int N = 1e5+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];
        int l = 0, r = n-1;
        while(l < r){
            while(l < n && a[l] < 0){
                l++;
            }
            while(r >= 0 && a[r] > 0){
                r--;
            }
            if(l < r){
                a[l] = -a[l];
                a[r] = -a[r];
            }
        }
        if(n == 1){
            cout<<"YES"<<endl;
        }else{
            bool flag = true;
           for(int i=1; i<n; i++){
               if(a[i-1] > a[i]){
                   flag = false;
                   break;
               } 
           }
           if(flag) cout<<"YES"<<endl;
           else cout<<"NO"<<endl;
        }
    }
    return 0;
}

B. Dorms War

题意 : 给一个长度为 n 的字符串 s , 一个长度为 k 的特殊字符串 c ,找到所有 si+1si+1 位置的字符在特殊字符 c 中, sisi 位置的字符会被删除, 最多操作几次。求2个特殊字符中间的距离

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;

int main() {
    int t;
    cin>>t;
    while(t--){
        int n;
        string s;
        cin>>n>>s;
        int k;
        bool st[26]; // 保存特殊字符
        memset(st, false, sizeof st);
        char c;
        cin>>k;
        for(int i=0; i<k; i++){
            cin>>c;
            st[c-'a'] = true;
        }
        vector<int> p;
        p.push_back(0);
        for(int i=0; i<n; i++){
            if(st[s[i]-'a']){ // 记录特殊字符的位置
                p.push_back(i);
            }
        }
        int res = 0;
        for(int i=1; i<p.size(); i++){
            res = max(res, p[i]-p[i-1]);
        }
        cout<<res<<endl;
    }
    return 0;
}

C. Where is the Pizza?

题意:给 2个数组, 数组a 和数组 b,数组 d 表示 d[i]=0d[i] = 0 时, c[i]c[i] 可以选择 a[i]b[i] a[i] 或 b[i], d[i]!=0d[i] != 0 时, d[i]d[i] 就选择了a[i]或者b[i]a[i] 或者 b[i] 中的一个,求 cc 数组有多少种组合。 分情况讨论

  1. d[i]!=0d[i] != 0, 表明 c[i]=d[i]c[i] = d[i]
  2. a[i]==b[i]a[i] == b[i], 表明 c[i]=a[i]c[i] = a[i]; 只有在 d[i]=0d[i] = 0 时, 可以提供 2*2 的答案。
例如 (1, 2), (2, 3),(3, 4),(4,1), 第一个坐标为 , 第二个坐标为 b,   
d数组  1      0     0      00      2     0      00      0     3      00      0     0      4
在这个循环中,只有一个位置被确认,其他位置也会被确认。
只有在全部为 0 的情况可以提供 * 2 的组合

若有 xx 个连通块没有被标识, 答案就是 pow(2,x) pow(2, x)。 可以使用并查集来做连通块是否被标识, 如果有被标识,将连通块挂到 0 下面。

#include <iostream>
#include <cstring>
#include <vector>
#include <set>
using namespace std;

const int N = 1e5+10;
int a[N], b[N], d[N], p[N];

int find(int u){
    if(u != p[u]){
        p[u] = find(p[u]);
    }
    return p[u];
}
int main() {
    int t;
    cin>>t;
    while(t--){
       int n;
       cin>>n;
       for(int i=0; i<n; i++) cin>>a[i];
       for(int i=0; i<n; i++) cin>>b[i];
       for(int i=0; i<n; i++) cin>>d[i];
       // 初始化并查集
       for(int i=0; i<=n; i++) p[i] = i;
       for(int i=0; i<n; i++){
           if(d[i] != 0){ // d[i] 不为零,证明有一个为被确定了,在这个连通快的数据都被确定了,挂到 0 下面
               p[find(0)] = find(d[i]);
           }
       }
       for(int i=0; i<n; i++){
           if(a[i] == b[i]){ // a[i] === b[i], 同样
               p[find(0)] = find(a[i]);
           }
       }
       for(int i=0; i<n; i++){  //  a 和 b 合并
           p[find(a[i])] = find(b[i]);
       }
       set<int> set;
       for(int i=1; i<=n; i++){
           if(find(0) == find(i)) continue;
           set.insert(find(i)); // 记录未被标记的父节点
       }
       long long res  =1;
       int mod = 1e9+7;
       for(int i=0; i<set.size(); i++){
           res *=2;
           res%=mod;
       }
       cout<<res<<endl;
    }
    return 0;
}

D. Very Suspicious

题意: 很多六边形,需要 n 个小三角形, 最少需要切多少刀。

image.png

image.png

多画一些可以得到 线条数为下标,数值为增加三角形的数量, 从 1 开始, [0, 2, 4, 4, 6, 8, 8, 10, 12] ... 这样的规律。 使用 p 数组, 下标为线条数, 数值为三角形的总数量,需要求 n 个三角形,需要的线条数量, 可以通过二分。

#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <queue>
#include <set>
#include <stack>
using namespace std;
const int N = 5e5+10;
int main(){
    

    long long cnt = 0, res = 0;
    vector<int> p(40000);
    int m = 40000;
    for(int i=0; i<=m; i++){
        if(i%3 == 1){
            cnt += 2;
        }
        if(i%3 == 2){
            cnt += 2;
        }
        res += cnt;
        p[i] = res;
    }
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        cout<<lower_bound(p.begin(), p.end(), n)-p.begin()+1<<endl;
    }
    return 0;
}

总结:
思维题,伤啊😢