当前位置: 首页 > article >正文

Codeforces Round 987 (Div. 2)题解 A~D

A- Penchick and Modern Monument

由于给定的数是非递增的,所以 h [ i ] ≥ h [ i + 1 ] h_[i]\geq h[i+1] h[i]h[i+1],如果 h [ i ] > h [ i + 1 ] h[i]>h[i+1] h[i]>h[i+1] 那么二者至少要改其一。因为最终要求的数是非递减的,所以最终数组内都是同一种数的方案是可行的。枚举最后会成为数组中的哪一个数即可。

void solve () {
    int n;
    cin >> n;

    vector <int> h(n + 1);
    for (int i = 1; i <= n; i++) cin >> h[i];


    int ans = INF;
    for (int i = 1; i <= n; i++) {
        int sum = 0;
         
        for (int j = 1; j <= n; j++) 
            if (h[j] != h[i]) sum ++;
         
        ans = min(sum, ans);
    }

    cout << ans << endl;
}
B- Penchick and Satay Sticks

假设 1 ∼ i − 1 1\sim i-1 1i1 已经放好了,如果 p [ i ] ≠ i p[i]\neq i p[i]=i 的话,现在要把 i i i 位置放好,当且仅当 p [ i + 1 ] = i p[i+1]=i p[i+1]=i 并且 p [ i ] = i + 1 p[i]=i+1 p[i]=i+1 时才能放好。

void solve () {
    int n;
    cin >> n;
    vector <int> p(n + 1);

    for (int i = 1; i <= n; i++) cin >> p[i];


    for (int i = 1; i <= n; i++) {
        if (p[i] == i) continue;

        // 找到 i 在哪
        int pos = -1;
        for (int j = i + 1; j <= n; j++) {
            if (p[j] == i) {
                pos = j;
                break;
            }
        }

        if (p[i] - p[pos] == 1) {
            swap (p[i], p[pos]);
        } else {
            cout << "NO" << endl;
            return;
        }
    }

    cout << "YES" << endl;
}
C-Penchick and BBQ Buns

这是一道构造题,先思考一个问题,是否存在 ( x , y ) (x,y) (x,y) 使得 x , y , x + y x,y,x+y x,y,x+y 都是平方数?答案是勾股数

再思考一个问题,是否存在 ( x , y , z ) (x,y,z) (x,y,z) 使得 x , y , z , x + y , y + z , x + y + z x,y,z,x+y,y+z,x+y+z x,y,z,x+y,y+z,x+y+z 都是平方数?我打了个表发现是没有的。

回到这个问题,也就是说,最多我们用三份相同的调料包,不可能用四份及以上的调料包。

n n n 是偶数的时候,显然可以相邻地放两个相同的数。

n n n 是奇数的时候,最小的一组勾股数是 9 , 16 , 25 9,16,25 9,16,25 至少需要 n ≥ 26 n\geq26 n26 时才能出现。

n n n 是大于 26 26 26 的奇数,我们可以在 1 , 10 , 26 1,10,26 1,10,26 处放同一个数,然后再在 23 , 27 23,27 23,27 处放同一个数,剩下的数就一直相邻放即可。

n n n 是小于 26 26 26 的奇数,不存在答案。

void solve () {
    int n;
    cin >> n;
    if (n < 27) {
        if (n & 1) cout << "-1" << endl;
        else {
            for (int i = 1; i <= n; i += 2) {
                cout << i << ' ' << i << ' ';
            }
            cout << endl;
        }
    } else {
        vector <int> a(n + 1, 0);

        if (n & 1) {
            a[1] = 1;
            a[10] = 1;
            a[26] = 1;
            a[23] = 2;
            a[27] = 2;
            int bnt = 3;

            for (int i = 2; i <= n; ) {
                if (a[i]) {
                    i ++;
                    continue;
                }
                a[i] = bnt;
                a[i + 1] = bnt;
                bnt ++;
                i += 2;
            }

            for (int i = 28; i <= n; i += 2) {
                a[i] = bnt;
                a[i + 1] = bnt;
                bnt ++;
            }

            for (int i = 1; i <= n; i++) {
                cout << a[i] << ' ';
            }
            cout << endl;
        } else {
            for (int i = 1; i <= n; i += 2) {
                cout << i << ' ' << i << ' ';
            }
            cout << endl;
        }
    }
}
D-Penchick and Desert Rabbit

兔子可以往后跳到比它当前更低的树,也可以往前跳到当前比它更高的树

这预示着,操作是可逆的、互通的

设集合 A A A 是兔子在 i i i 树能跳到的所有树的集合,显然从 A A A 内的任意一棵树都一定能跳到 i i i 树。

现在的问题就是,我们怎样地遍历才能不超时、不缺漏地合并所有集合

让我们推演一下:

对于一棵最高的树 p 1 p_1 p1,它可以直接跳到它后面所有的树上,所以直接遍历即可。

然后找到次高的树 p 2 p_2 p2,需要判断是否这棵树能跳到最高的树后面,如果可以的话,那么从 p 2 ∼ p 1 p_2\sim p_1 p2p1 都可以合并。

不断重复这个过程,又因为每个数只会被合并一次,所以时间是 O ( n ) O(n) O(n) 的。

如何找到最高、次高、 ⋯ \cdots 的位置?由于值域是 1 ∼ n 1\sim n 1n,所以可以开一个 O ( n ) O(n) O(n) 的桶。

看似上面一直说合并集合,实际上我们可以发现,当前最高的树只能往右边跳,我们只要维护上一个集合的左端点,以及维护上一个集合的最小值即可。

void solve () {
    int n;
    cin >> n;

    vector <int> a(n + 1);
    vector <int> v[n + 1]; // 桶排序
    vector <int> ans (n + 1); // 用来计答案

    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        v[a[i]].emplace_back(i);
    }

    int l = n + 1, minn = INF; // 最开始上个集合的左端点是 n + 1,最小值无穷大。

    for (int i = n; i >= 1; i--) {

        for (int j = v[i].size() - 1; j >= 0; j--) { // 遍历所有大小为 i 的桶
            if (v[i][j] >= l) continue; // 如果这个值在上个集合内部就跳过
            ans[v[i][j]] = i; // 首先将答案初始化为自身

            if (i > minn) { // 如果当前的值大于上个集合内部的最小值
                for (int k = v[i][j]; k < l; k++) { // 那么它能去的最大值就是上个集合的最大值
                    ans[k] = ans[l]; // ans[l] 是上个集合内最大值,上个集合内所有数的答案都是 ans[l]
                    minn = min(minn, a[k]); // 更新最小值
                }
                l = v[i][j]; // 更新左端点
            } else {
                int temp = INF; // 如果无法访问到上一个集合内部
                for (int k = v[i][j]; k < l; k++) { // 那么后续的集合肯定无法访问到上一个集合内部
                    ans[k] = ans[v[i][j]]; // 此时新开一个集合
                    temp = min(temp, a[k]);
                }
                minn = temp; 
                l = v[i][j];
            }
        }

    }

    for (int i = 1; i <= n; i++) {
        cout << ans[i] << ' ';
    }

    cout << endl;

}

http://www.kler.cn/a/525651.html

相关文章:

  • 使用冒泡排序模拟实现qsort函数
  • 【Redis】 String 类型的介绍和常用命令
  • 【C语言】内存函数
  • Spring Boot - 数据库集成05 - 集成MongoDB
  • sudo nvim /path/yourfile, sudo: nvim: command not found
  • Linux 4.19内核中的内存管理:x86_64架构下的实现与源码解析
  • 【PowerShell专栏】实现Terminal工具的安装
  • 【电工基础】4.低压电器元件,漏电保护器,熔断器,中间继电器
  • 爬虫基础(三)Session和Cookie讲解
  • 基于单片机的景区人数实时统计系统设计
  • SpringBoot 整合 SSM
  • openRv1126 AI算法部署实战之——ONNX模型部署实战
  • Java集合面试总结(题目来源JavaGuide)
  • mysql 学习2 MYSQL数据模型,mysql内部可以创建多个数据库,一个数据库中有多个表;表是真正放数据的地方,关系型数据库 。
  • 【Block总结】SCSA,探索空间与通道注意力之间的协同效应|即插即用
  • Android createScaledBitmap与Canvas通过RectF drawBitmap生成马赛克/高斯模糊(毛玻璃)对比,Kotlin
  • PyTorch 快速入门
  • Haproxy入门学习二
  • DeepSeek 模型全览:探索不同类别的模型
  • 字符串,集合
  • MySQL数据库(二)
  • redis数据安全与性能保障
  • .gitignore 文件的使用
  • Windows平台免费艺术签名设计工具:一键生成书法级个性签名
  • AIGC时代的Vue或React前端开发
  • 搜索与图论复习1