OscarWen
喜欢到处随意折腾

Educational Codeforces Round 105题解

第一次打cf的比赛是教育轮,实在被教育了一顿,就过了一题,好好复盘一下。

A. ABC string
签到题,但我打了半小时就离谱。
关键就是,打头的字母一定对应“(”,结束的字母一定对应“)”

B. Berland Crossword
题面大概意思是在一个边长n正方形内,里面有n*n个正方形方格,在四个边界按要求的数量进行涂色,如果可以成功涂色出来就输出yes,反之输出no。
写的时候没有注意到四个角是解决问题的关键,就是说,如果造成涂色失败,都是因为在角的涂色影响了其他的边。那么就是说,只要我们处理完那些必定要涂角的边,再去看看每个边的中间部分要涂的格子数量有没有小于0,如果没有就是可以成功涂色。
官方给的解题思路是遍历16种四角涂色方案,在每一种方案下,根据要涂的角确定每一条边的中间部分要涂多少,若合法就是yes。

C. 1D Sokoban
这道题里面,一条线上有很多箱子,线上有若干特殊点,只能向前推,不能拉,也不能搬起箱子越过其他箱子,但可以推着若干堆叠的箱子前进。
一个关键是:正负两边是完全一样的一个问题,可用一种算法解决。还有一个关键:从初始阶段,将第一个箱子推到前面的第一个特殊点,不会让结果更坏。而且,从当前特殊点再推到下一个特殊点过程中产生的答案,均可以在推到某个特殊点时取得。
因此,可以得到一个朴素的算法,将第一个箱子推到每一个特殊点,然后计算重合的数量,取最大值即可。为了优化,可以先计算出su代表第i个箱子到最后一个箱子与特殊点重合的数量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <iostream>
#include <algorithm>
#include <vector>
 
using namespace std;
 
int t;
int n, m;
 
int calc(vector<int>& a, vector<int>& b){
    int n = a.size();
    int m = b.size();
    vector<int> su(n + 1);
    int r = m - 1;
    for(int i = n - 1; i >= 0; i--){
        su[i] = su[i + 1];
        while(r >= 0 && a[i] < b[r]) r--;
        if(r >= 0 && a[i] == b[r]){
            su[i]++;
        }
    }
 
    r = 0;
    int pile = 0;   //一起被推动的箱子数量
    int res = 0;
    for(int l = 0; l < m; l++){
        while(pile < n && a[pile] < b[l] + pile) 
            pile++; //来到一个特殊点,计算一起推动箱子数
        while(r < m && b[r] - b[l] < pile) 
            r++;    //计算堆叠的箱子数覆盖了多少个特殊点
        res = max(res, r - l + su[pile]);
    }
    return res;
}
 
int main(){
    cin >> t;
    while(t--){
        cin >> n >> m;
        vector<int> a(n), b(m);
        for(int i = 0; i < n; i++)
            cin >> a[i];
        for(int i = 0; i < m; i++)
            cin >> b[i];
        vector<int> al, bl, ar, br;
        for(int i = 0; i < n; i++){
            if(a[i] > 0)
                ar.push_back(a[i]);
            else
                al.push_back(-a[i]);
        }
        for(int i = 0; i < m; i++){
            if(b[i] > 0)
                br.push_back(b[i]);
            else
                bl.push_back(-b[i]);
        }
        reverse(al.begin(), al.end());
        reverse(bl.begin(), bl.end());
        cout << calc(al, bl) + calc(ar, br) << endl;
    }
    return 0;
}

相关博文