解题思路:
方法1:由于数据比较小,所以可以用循环暴力破解即可。但是这一种方法效率比较低。如果数据比较大,则肯定超时。
方法2:涉及到数论。使用等差数列公式,设第一项为:left, 最后一项为:right, 连续自然数和为M。
使用等差数列求和可得:(left+right)*(right-left+1)=2*M
再假设:k1=rihgt-left+l, k2=left+right (k1<k2)
此时把问题转化成了求两个整数k1,k2的乘积是2M。
解方程可得: left=(k2-k1+1)/ 2 , right =(k1+k2-1)/ 2;
值得注意的是因为left和right是自然数,这两个方程有解,当且仅当k1和k2一个奇数一个偶数;
也就是说要满足: k1%2!=k2%2,对于k1从sqrt(2M)开始到1枚举即可。
同时要注意left必须小于right。
方法3:涉及到数论。使用等差数列公式,设第一项为:x, 最后一项为:x+n, 连续自然数和为M。
使用等差数列求和可得:
(2x + n)(n + 1)/2 =M
推导出 (2x + n)(n + 1) =2M,则n从sqrt(2M)开始到1枚举即可。那么x为多少呢?请看:
==> 2x + n = 2M / (n + 1)
==> 2x = 2M / (n + 1) - n
==> x = ( 2M / (n + 1) - n ) /2
又因为x为自然数数,所以,2M一定能被 (n + 1)整除,即2M % (n + 1)一定为零,
另外,同理:(2M / (n + 1) - n ) % 2一定也为0。
参考代码:
//方法1:暴力破解
#include<bits/stdc++.h>
using namespace std;
int main()
{
int M,a;
while(cin>>M)
{
for(a=1;a<=M/2;a++)
{
int sum=a;
for(int b=a+1;;b++)
{
sum=sum+b;
if(sum>M)
break;
if(sum==M)
{
cout<<a<<" "<<b<<endl;
break;
}
}
}
cout<<endl;
}
return 0;
}//方法2:用数论解决,效率高。如果数据比较大,不超过1e19,可以把int修改为 long long 即可。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int M;
while(cin>>M)
{
M=2*M;
for(int k1=sqrt(M);k1>=1;k1--)
{
if(M%k1==0)
{
int k2=M/k1;
if(k1%2!=k2%2)
{
int left=(k2-k1+1)/2;
int right=(k1+k2-1)/2;
if(left<right)
cout<<left<<" "<<right<<endl;
}
}
}
cout<<endl;
}
return 0;
}//方法3:用数论解决,效率高。如果数据比较大,不超过1e19,可以把int修改为 long long 即可。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int M;
while(cin>>M)
{
M=2*M;
for(int n=sqrt(M);n>=1;n--)
{
if( M%(n+1)==0 && ( M/(n+1)-n )%2==0 )
{
int x=(M/(n+1)-n)/2;
if(x>0)
cout<<x<<" "<<x+n<<endl;
}
}
cout<<endl;
}
return 0;
}0.0分
3 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复