题目描述:
neuq最近推出了一套具有特殊意义的邮票,邮票的价值是从1分到N分。并且每张邮票的价值都不相同。
谷学长看中了这套邮票,可是一掏兜发现自己只有M分。但是他非常想买,于是他决定买总价值刚好为M分的邮票,但谷学长不希望他买的邮票断断续续,所以他还希望能够买从x分到y分连续的y-x+1张邮票。
你的任务是求出所有符合要求的方案,以[x,y]的形式输出。
输入:
输入包含多组数据,每组数据只有一行,包含两个数N和M(1<=N,M<=10^9)。
输出:
对于每组输入数据,每行输出包含一个合法方案:[x,y]。按x值从小到大输出。
每组输出数据不含任何空格。
样例输入
20 15
样例输出
[1,5]
[4,6]
[7,8]
[15,15]
分析:开始考虑这道题是想用两层循环,外层遍历选定邮票首项,内层遍历之后的尾项,满足和为M。但是显然效率低下。
考虑到邮票是从1~N的等差数列排列,可以利用等差数列公式。
按照等差数列计算,连续数列有i个数,首数为x,和为n=(2x+i-1)*i/2,解得x=(2n/i-i+1)/2,注意x>0且i为整数,可得i的取值范围为[1, sqrt(2*n)],又x为整数,故2n/i为整数,且(2n/i-i+1)/2为整数。
#include"stdio.h"
#include"math.h"
int stamp(int n, int m);
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))//因为题目没有说明何时输入结束 所以以EOF为结束 最好用~ 因为用!EOF说内存超限
{
stamp(n,m);
}
return 0;
}
int stamp(int n,int m)
{
int temp,i;
for(i = sqrt(2*m); i>=1; i--)//注意从i= 1 开始 而不是i= 2 否则不包含【m,m】
{
if((2*m)%i==0)//即 2*m/i为一个整数
{
temp = m*2/i-i+1;
if(temp%2 == 0)//temp = 连续数列的首项的2倍 保证可以整除
{
if((temp/2+i-1)<=n)//保证连续邮票的尾项不超过总数
{
printf("[%d,%d]\n",temp/2,temp/2+i-1);
}
}
}
}
}