[题解]CF899C.Dividing the numbers(ACGO)[codeforces 02]

目录

题目描述

输入格式

输出格式

输入输出样例

说明/提示

Dividing the numbers-普及/提高-题目-ACGO题库

题目理解:

代码:


题目描述

Petya has 𝑛n integers: 1,2,3,...,𝑛1,2,3,...,n . He wants to split these integers in two non-empty groups in such a way that the absolute difference of sums of integers in each group is as small as possible.

Help Petya to split the integers. Each of 𝑛n integers should be exactly in one group.

输入格式

The first line contains a single integer 𝑛n ( 2<=𝑛<=600002<=n<=60000 ) — the number of integers Petya has.

输出格式

Print the smallest possible absolute difference in the first line.

In the second line print the size of the first group, followed by the integers in that group. You can print these integers in arbitrary order. If there are multiple answers, print any of them.

输入输出样例
  • 输入#1

    4
    

    输出#1

    0
    2 1 4 
    
  • 输入#2

    2
    

    输出#2

    1
    1 1 
    
说明/提示

In the first example you have to put integers 11 and 44 in the first group, and 22 and 33 in the second. This way the sum in each group is 55 , and the absolute difference is 00 .

In the second example there are only two integers, and since both groups should be non-empty, you have to put one integer in the first group and one in the second. This way the absolute difference of sums of integers in each group is 11 .

Dividing the numbers-普及/提高-题目-ACGO题库

题目理解:

这是一个典型的求解“最小绝对差分”的问题。我们可以从以下几个角度来思考解题思路:

  1. 理解题目:题目要求我们将1到n的整数分成两个非空组,使得两组之和的绝对差最小。这意味着我们需要尽可能平均地分配这些数字。

  2. 观察样例:对于输入为4的情况,我们注意到1+4和2都是5,这样可以得到0的绝对差。对于输入为2的情况两个非空组,所以每个组只能有一个数,导致绝对差为1。

  3. 寻找规律:对于奇数个数的情况,中间的数字放在哪一组都不会改变其他数字的分配,因此它对最小化绝对差没有影响。我们可以先不管它,先处理偶数个数的情况。

  4. 算法设计:对于偶数个数,我们可以尝试将最大的和最小的配对,次大的和次小的配对,以此类推,这样可以最大化每组的和的接近程度。对于奇数个数,我们可以先将中间的数放到一边,然后按照偶数个数的情况处理剩下的数,最后再将中间的数加到任意一组。

  5. 实现策略:可以使用一个简单的贪心策略,先遍历数组,找到最大值和最小值,将它们分到不同的组,然后去掉这两个数,重复这个过程,直到所有数都被分到组里。

  6. 复杂度分析:这个算法的时间复杂度是O(n),因为我们只遍历一次数组。空间复杂度是O(1),因为我们不需要额外的空间来存储数据。

代码:

以下是网络代码:899C - Dividing the numbers-CSDN博客

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n,sum,cnt,j;
    while(cin>>n)
    {
        cnt=0;
        sum=n*(n+1)/2;
        if(sum%2==0) puts("0");
        else puts("1");
        cout<<n/2<<" ";
        for(int i=n; i>1; i-=2)
        {
            if((++cnt)%2) j=0;
            else j=1;
            cout<<i-j<<" ";
        }
        puts("\n");
    }
    return 0;
}

这是AI系统给出的建议:

尽管你的解决方案是有效的,但还有一些优化和风格上的建议:

  1. 使用const关键字:当变量在声明时就确定不会改变时,可以使用const关键字,如const int n。这有助于提高代码可读性和避免意外修改。

  2. 使用std::ios_base::sync_with_stdio(false)cin.tie(nullptr):在大型输入/输出操作中,这可以帮助提高程序性能,因为它禁用了C++ I/O流与C标准I/O流之间的同步,并取消了cin与cout之间的默认连接。

  3. 使用范围基础for循环(range-based for loop):对于遍历数组或集合,范围基础for循环可以简化代码,如for (int i 2, 3, 4})。不过在这个问题中,你使用的是递减循环,所以不需要改变。

  4. 去除无用的变量:变量j在这个例子中并不必要,因为你可以直接在cout语句中计算i - (cnt % 2)

考虑到以上建议,你的代码可以修改如下:

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

int main() {
    const int n;
    cin >> n;
    int sum = n * (n + 1) / 2;
    cout << abs(sum % 2) << endl;
    cout << n / 2 << " ";
    for (int i = n; i > 1; i -= 2) {
        cout << i - (n % 2) << " ";
    }
    cout << endl;

    return 0;
}

这个版本的代码同样正确地解决了问题,同时减少了不必要的变量和提高了可读性。在实际的信奥竞赛中,这样的代码效率已经足够高,不需要进一步优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ysjt | 深

谢谢你!你的支持是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值