• CodeForces Round #501 (div.3) A~E2


    A. Points in Segments(暴力)

    题意:

    给定 n 个子区间和 m 个 1~m 的总区间,问有哪些点没有被给定的子区间覆盖,输出未被覆盖的点。

    思路:

    暴力模拟即可。

    遍历整个区间,用一个标记数组来记录被覆盖了的点,最后输出未被标记的点。

    代码如下:

    #include 
    #define ll long long
    using namespace std;
    const int N = 110;
    
    int a[N], vis[N];
    
    int main()
    {
        int n, m;
        cin >> n >> m;
    
        int sum = m;
        for (int i = 1; i <= n; i++){
            int l, r;
            cin >> l >> r;
            for (int j = l; j <= r; j++){
                if (vis[j] == 0){
                    vis[j] = 1;
                    sum--;
                }
            }
        }
        
        if (sum == 0){
            cout << sum << endl;
        }
        else {
            cout << sum << endl;
            for (int i = 1; i <= m; i++){
                if (vis[i] == 0){
                    cout << i << ' ';
                }
            }
            cout << endl;
        }
        
        return 0;
    }
    
    • 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

    B. Obtaining the String(排序)

    题意:

    给定两个字符串 st ,规定每次只能交换相邻的字符串,要求将 s 变成 t

    输出交换的次数,和每次交换时该对字符中前面字符的位置。

    思路:

    冒泡排序

    对字符串 t 依次遍历,当发现 t[i] != s[i] 时,从 i + 1 位置开始遍历字符串 s ,找到 s[j] == t[i] ,记录其位置,并从后往前依次交换,存下每次交换时前面字符的位置。

    继续重复上述步骤,直至两个字符串相同为止。

    代码如下:

    #include 
    #define ll long long
    using namespace std;
    const int N = 2e5 + 10;
    
    int main()
    {
        int n;
        cin >> n;
        string s, t;
        cin >> s >> t;
        s = ' ' + s; t = ' ' + t;
    
        vector<int> ans;
        for (int i = 1; i <= n; i++){
            if (s[i] == t[i]) continue;
            int p = 0;
            for (int j = i + 1; j <= n; j++){
                if (s[j] == t[i]){
                    p = j;
                    break;
                }
            }
    
            if (p == 0){
                cout << -1 << endl;
                return 0;
            }
    
            for (int j = p - 1; j >= i; j--){
                swap(s[j], s[j + 1]);
                ans.push_back(j);
            }
        }
    
        cout << ans.size() << endl;
        for (auto x : ans){
            cout << x << ' ';
        }
        cout << endl;
    
        return 0;
    }
    
    • 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

    C. Songs Compression(贪心)

    题意:

    将手机中的歌曲存进U盘中,U盘的容量可能不够,可以对每首歌曲压缩,判断是否可以将手机中的全部歌曲都存进U盘中,输出最少的压缩次数。

    给定 n 首歌和一个容量为 m 的U盘,接下来 n 行,每一行代表歌曲的初始大小和压缩后的大小。

    思路:

    先读入所有歌曲的初始大小和压缩后的大小,并且用数组 c[i] 把大小差值存储起来。

    再判断未被压缩时能否存进U盘中,以及压缩后能否存进U盘中。

    如果全部压缩后能存进U盘中,再对差值数组 c[i] 依次从大到小排序,然后逐个压缩,直到U盘可以存下为止,输出压缩次数即可。

    代码如下:

    #include 
    #define ll long long
    using namespace std;
    const int N = 2e5 + 10;
    
    ll a[N], b[N], c[N];
    
    int main()
    {
        int n, m;
        cin >> n >> m;
    
        ll sum1 = 0, sum2 = 0;
        for (int i = 1; i <= n; i++){
            cin >> a[i] >> b[i];
            c[i] = a[i] - b[i];
            sum1 += a[i];
            sum2 += b[i];
        }
    
        if (sum2 > m){
            cout << -1 << endl;
            return 0;
        }
        if (sum1 <= m){
            cout << 0 << endl;
            return 0;
        }
    
        sort(c + 1, c + 1 + n, greater<int>());
    
        int res = 0;
        for (int i = 1; i <= n; i++){
            sum1 -= c[i];
            res++;
            if (sum1 <= m){
                cout << res << endl;
                return 0;
            }
        }
    
        return 0;
    }
    
    • 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

    D. Walking Between Houses(构造)

    题意:

    给定一排 n 个房子,编号 1 ~ n,现在需要搬家 k 次,搬家的总距离为 s,每次搬家的距离为 |x - y|。

    现要求构造一个转移序列,序列中每个元素为搬家后的地址,满足有 k 个元素,总距离为 s。

    思路:

    首先对其判断:

    ① 当 s < k 时构造不出来。因为每次搬家都至少移动 1 的距离,总共最少都会移动 k 个距离,超过了总距离 s,一定构造不出来。

    ② 当 k * (n - 1) < s 时也构造不出来。n - 1 为每次搬家最大的移动距离,如果每次移动距离都最大,移动 k 次后也无法满足总距离 s,则也一定构造不出来。

    对于其他情况,选择每次移动的距离为 s - kn - 1 中比较小的那一个,再用总距离减去当前走的距离,若当前位置加上当前要移动的距离大于 n,则往回走。如此循环,直至总距离为 0 即可。

    代码如下:

    #include 
    #define ll long long
    using namespace std;
    const int N = 2e5 + 10;
    
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
    
        ll n, k, s;
        cin >> n >> k >> s;
    
        if ((n - 1) * k < s || s < k){
            cout << "NO" << endl;
            return 0;
        }
    
        cout << "YES" << endl;
        int p = 1;  //p表示每次移动后的位置
        while (k--)
        {
            int dist = min(s - k, n - 1);  //表示每次移动的距离
            p -= dist;
            if (p + dist <= n)
                p += dist;
            else 
                p -= dist;
    
            cout << p << ' ';
        }
        cout << endl;
    
        return 0;
    }
    
    • 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

    E1. Stars Drawing (Easy Edition)(模拟)

    题意:

    规定一种星星图:在图案最中间有一个 * 号,并且从中心向四周(上下左右)延伸出相同长度的 * 号,延伸出去的长度即为星星图的大小。

    现在给定一个 n * m 的仅包含 *. 的图案,判断能否用若干个星星图画出给定的图案。

    如果可以,输出星星图的中心坐标和大小,否则输出 -1.

    思路:

    大模拟。

    两遍循环遍历整个图,对于每个为 * 的地方,判断从当前位置能延伸出去几个星星,如果有星星,就标记每个延伸到的星星,用 vector 存储坐标和当前星星图的大小,没有则跳过。

    如果遍历完整个图后,还有星星没有被标记,则代表不能用若干个星星图绘制出所给定的图案,输出 -1,否则输出坐标和所用到的星星图的大小。

    代码如下:

    #include 
    #define ll long long
    using namespace std;
    const int N = 110;
    
    int n, m;
    char mp[N][N];
    int vis[N][N];
    
    //用结构体存储坐标和大小
    struct pos
    {
        int x, y, size;
    };
    
    vector<pos> v;
    
    //检查当前星星的位置
    bool check(int x, int y)
    {
        if (x >= 1 && x <= n && y >= 1 && y <= m && mp[x][y] == '*')
            return true;
        return false;
    }
    
    int get_size(int x, int y)
    {
        int size = 0;
        for (int i = 1; ; i++){
            //判断上下左右是否都有可延伸的星星
            if (check(x - i, y) && check(x + i, y) 
                && check(x, y - i) && check(x, y + i))
            {
                vis[x][y] = 1;
                size = i;
                vis[x - i][y] = vis[x + i][y] = vis[x][y - i] = vis[x][y + i] = 1;
            }
            else break;
        }
    
        return size;
    }
    
    int main()
    {
        cin >> n >> m;
    
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= m; j++)
                cin >> mp[i][j];
    
        for (int i = 1; i <= n; i++){
            for (int j = 1; j <= m; j++){
                if (mp[i][j] == '*'){
                    int size = get_size(i, j);
                    
                    //只有星星图大小大于0才合法
                    if (size > 0) v.push_back({i, j, size});
                }
            }
        }
    
        //判断是否有多余的星星没有延伸到,如果有则无法绘制成所给图案
        int f = 1;
        for (int i = 1; i <= n; i++){
            for (int j = 1; j <= m; j++){
                if (mp[i][j] == '*' && vis[i][j] == 0){
                    f = 0;
                    break;
                }
            }
        }
    
        if (f){
            cout << v.size() << endl;
            for (auto ans : v){
                cout << ans.x << ' ' << ans.y << ' ' << ans.size << endl;
            }
        }
        else {
            cout << -1 << endl;
        }
    
        return 0;
    }
    
    • 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
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85

    E2. Stars Drawing (Hard Edition)(模拟)

    题意:

    与上题题意一样,不同的是把图的规模从 100 变成了 1000。

    思路:

    与上题的代码略有不同,因为图的规模变大了,再用 cin, cout 会导致超时,所以只需对输入输出做优化即可。

    代码如下:

    #include 
    #define ll long long
    using namespace std;
    const int N = 1100;
    
    int n, m;
    char mp[N][N];
    int vis[N][N];
    
    struct pos
    {
        int x, y, size;
    };
    
    vector<pos> v;
    
    bool check(int x, int y)
    {
        if (x >= 0 && x < n && y >= 0 && y < m && mp[x][y] == '*')
            return true;
        return false;
    }
    
    int get_size(int x, int y)
    {
        int size = 0;
        for (int i = 1; ; i++){
            if (check(x - i, y) && check(x + i, y)
                && check(x, y - i) && check(x, y + i))
            {
                vis[x][y] = 1;
                size = i;
                vis[x - i][y] = vis[x + i][y] = vis[x][y - i] = vis[x][y + i] = 1;
            }
            else break;
        }
    
        return size;
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
    
        for (int i = 0; i < n; i++)
            scanf("%s", mp[i]);
    
        for (int i = 0; i < n; i++){
            for (int j = 0; j < m; j++){
                if (mp[i][j] == '*'){
                    int size = get_size(i, j);
                    if (size > 0)
                        v.push_back({i + 1, j + 1, size});
                }
            }
        }
    
        int f = 1;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++)
                if (mp[i][j] == '*' && vis[i][j] == 0){
                    f = 0;
                    break;
                }
    
        if (f){
            printf("%d\n", v.size());
            for (auto ans : v){
                printf("%d %d %d\n", ans.x, ans.y, ans.size);
            }
        }
        else {
            puts("-1");
        }
    
        return 0;
    }
    
    • 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
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

  • 相关阅读:
    Docker从了解到部署应用的详细教程
    C语言实验二 数据类型、运算符和表达式
    Java课程设计:基于swing的贪吃蛇小游戏
    《HelloGitHub》第 90 期
    代码随想录Day51 完结篇 LeetCode T84 柱状图的最大矩形
    ElasticSearch--查看健康状态(health)的方法(API)
    javascript二维数组(21)执行异步HTTP(Ajax)请求的方法($.get、$.post、$getJSON、$ajax)
    算法 滑动窗口
    Servlet原理及应用
    【GlobalMapper精品教程】014:矢量线图层的创建及数字化操作
  • 原文地址:https://blog.csdn.net/qq_59904473/article/details/127663652