2023/11/21 连续正整数(位运算)

【问题描述】

一个正整数有可能可以被表示为n(n>=2)个连续正整数之和,如:
15=1+2+3+4+5
15=4+5+6
15=7+8
请编写程序,根据输入的任何一个正整数,找出符合这种要求的所有连续正整数序列。

【输入形式】

从控制台输入一个正整数(小于等于10000)。

【输出形式】

在标准输出上输出符合题目描述的全部正整数序列,每行一个序列,每个序列都从该序列的最小正整数开始、以从小到大的顺序打印。如果结果有多个序列,按各序列的最小正整数的大小从小到大打印各序列。此外,序列不允许重复,序列内的整数用一个空格分隔,每个序列最后一个整数后要有一个空格。如果没有符合要求的序列,输出“none”。

【输入样例1】

15

【输出样例1】

1 2 3 4 5
4 5 6
7 8

【输入样例2】

16

【输出样例2】

none

【样例说明】

样例1输入的是15,其连续正整数序列有3个,分别输出。样例2输入的是16,没有连续的正整数序列之和为16,所以输出字符串:none。

#include<iostream>
using namespace std;

int main()
{
	int n, i, sum, temp = 0;
	cin >> n;
	if ((n & (n - 1)) != 0)
	{
		for (i = 1; i < n; i++)
		{
			temp = i;
			sum = 0;
			for (int j = i; j < n; j++)
			{
				sum += j;
				if (sum == n)
				{
					for (int m = i; m <= j; m++)
					{
						cout << m << " ";
					}
					cout << endl;
					break;
				}

			}
			i = temp;
		}

	}
	else
	{
		cout << "none" << endl;
	}



	return 0;
}

我原本的代码是先判断n是否是2的次方项,这里使用了位运算,下面贴出位运算的一些高级操作

4 负数的位运算

首先,我们要知道,在计算机中,运算是使用的二进制补码,而正数的补码是它本身,负数的补码则是符号位不变,其余按位取反,最后再+ 1 +1+1得到的, 例如:

15  原码:00001111   补码:00001111 

− 15 原码:10001111    补码:11110001 

那么对于负数的位运算而言,它们的操作都是建立在补码上的,得到的运算结果是补码,最后将补码结果转化成一个普通的十进制数结果。但需要注意的是,符号位是需要参与运算的,而在左移右移操作中,负数右移补1 11,左移右边补0 00。例如对于− 15 -15−15,其补码为11110001 , 11110001,11110001,右移一位( − 15 > > 1 ) (-15>>1)(−15>>1)得到的是11111000 1111100011111000,即− 8 -8−8,其他的同理。

这里我们介绍几个特殊的性质:

  • 快速判断是否为− 1 -1−1

在链式前向星中,我们初始化h e a d headhead数组为− 1 -1−1,最后判断是否遍历完u uu的所有边时,即判断i ii是否为− 1 -1−1,我们直接用∼ i \sim i∼i即可。原因就在于− 1 -1−1的补码是11111111 1111111111111111,按位取反就变为00000000 0000000000000000,这实际上就是0 00。

  • 取最低位的1,lowbit函数

也就是x & ( − x ) x\&(-x)x&(−x),这在树状数组中起着巨大作用,这里指路一篇树状数组讲解b l o g blogblog:点这里,我们来证明一下,这里取x = 15 x=15x=15,对于15 & ( − 15 ) 15\&(-15)15&(−15),我们知道,在补码上进行运算得到的是00000001 0000000100000001,需要注意二元运算的符号位我们需要进行运算。
————————————————
版权声明:本文为CSDN博主「unique_pursuit」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/hzf0701/article/details/117359478

第二层第三层从1开始连续正整数加起来,如果等于n就输出。三层循环很复杂,下面是一位大佬写出的代码。

这段代码是一个Java程序,用于解决一个问题:找出一个正整数能够表示为n个连续正整数之和的所有可能序列。

程序首先从控制台输入一个正整数,然后通过计算找出符合要求的连续正整数序列,并将结果输出到标准输出。

程序的主要逻辑如下:

1. 首先,定义一个Scanner对象用于从控制台读取输入。
2. 接着,读取输入的正整数并保存到变量input中。
3. 定义变量length为2,表示连续正整数序列的最低长度。
4. 定义变量odd为false,用于标识当前序列的长度是奇数还是偶数。
5. 计算平均值ans,即input除以length。
6. 进入一个循环,循环条件是ans减去length的一半小于0,即平均值小于长度的一半。
7. 在循环中,根据奇偶标识符odd判断当前序列的长度是奇数还是偶数。
8. 如果长度是奇数,判断平均值是否为整数,如果是则调用output函数输出结果。
9. 如果长度是偶数,判断平均值是否为0.5结尾,如果是则调用output函数输出结果。
10. 更新奇偶标识符odd和长度length,继续下一次循环。
11. 循环结束后,程序执行完毕。

output函数用于输出结果,接收三个参数:奇偶标识符odd、平均值ans和长度length。该函数的逻辑如下:

1. 根据奇偶标识符odd和平均值ans计算序列的起始值start。
2. 如果长度是奇数,起始值为平均值减去长度的一半(去尾法)。
3. 如果长度是偶数,起始值为平均值加1减去长度的一半(进一法)。
4. 使用一个循环,循环次数为长度length。
5. 在循环中,依次输出起始值start,并将start加1。
6. 输出完所有的正整数后,函数执行完毕。

总结:这段代码通过计算平均值和判断奇偶性来找出符合要求的连续正整数序列,并将结果输出。

下面是自己根据上面代码写的: 

#include<iostream>
#include<cmath>
#include<cstring>
#include<fstream>
#include<iomanip>
using namespace std;

int print(bool odd, double ans, int length);
int main()
{
	int N;
	cin >> N;
	bool odd = false;
	int length = 2;
	double ans = N * 1.0 / length;
	int count = 0;
	while (ans - length / 2 >= 0)
	{
		if (odd)
		{
			if (ans - (int)ans == 0)
			{
				print(odd, ans, length);
				count++;
			}
		}
		else
		{
			if (ans - (int)ans == 0.5)
			{
				print(odd, ans, length);
				count++;
			}
		}
		odd = !odd;
		length++;
		ans = N * 1.0 / length;
	}
	if (count == 0)
	{
		cout << "none" << endl;
	}
	return 0;
}
int print(bool odd, double ans, int length)
{
	int start;
	if (odd)
	{
		start = (int)ans - length / 2;
	}
	else
	{
		start = (int)ans + 1 - length / 2;
	}
	if (start)
	{
		for (int i = 0; i < length; i++)
		{
			cout << start + i << " ";
		}
		cout << endl;
	}
	return 0;
}

或者这个

//sum=(2*i+k-1)*k/2=sum
#include <iostream>
using namespace std;

void printSequence(int start, int length) {
    for (int i = 0; i < length; i++) {
        cout << start + i << " ";
    }
    cout << endl;
}

int main() {
    int N;
    cin >> N;
    bool found = false;

    // 尝试所有可能的序列长度
    for (int length = 2; length * (length + 1) / 2 <= N; length++) {
        // 计算当前长度下的起始点
        if ((N - (length * (length - 1) / 2)) % length == 0) {
            int start = (N - (length * (length - 1) / 2)) / length;
            printSequence(start, length);
            found = true;
        }
    }

    if (!found) {
        cout << "none" << endl;
    }

    return 0;
}

不过有个问题,这些输出都是逆序的(TAT)

本来应该是

这个问题我目前也没想到prprpr(主要是没咋想)等这几天忙后可能会好好想想

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值