纪念邮票
Time Limit: 1000MS
Memory Limit: 10000K
Description
邮局最近推出了一套纪念邮票,这套邮票共有N张,邮票面值各不相同,按编号顺序为1分,2分,…,N分。
小杭是个集邮爱好者,他很喜欢这套邮票,可惜现在他身上只有M分,并不够把全套都买下。他希望尽量买,最好刚好花光所有钱。作为一个集邮爱好者,小杭也不想买的邮票编号断断续续。所以小杭打算买面值a分至b分的b-a+1张连续的邮票,且总价值刚好为M分。
你的任务是求出所有符合要求的方案,以[a,b]的形式输出。
Input
输入文件只有一行,包含两个数N和M(1≤N,M≤10^9)。(10^9表示10的9次方)
Output
输出文件每行包含一个合法方案:[a,b]。按a值从小到大输出。
Sample Input
20 15
Sample Output
[1,5]
[4,6]
[7,8]
[15,15]
Hint
No hint.
Source
这题乍一看并不难,很容易想到下面的代码:
#include<iostream>
using namespace std;
int main()
{
int n,m;
cin>>n>>m;
int a;
int b;
for(a=1;a<=n;a++)
for(b=a;b<=n;b++)
{
int sum=0;
for(int i=a;i<=b;i++)
sum+=i;
if(sum==m)
cout<<"["<<a<<","<<b<<"]\n";
}
}
但是因为数据范围(1≤N,M≤10^9)过大,明显很容易超时,故不能采用。
再次分析,很容易想到求和公式,试着将其变形:2*M = (a+b) * (b-a+1);等式右边两项奇偶性不同。即如果找到两个因数i,j,使得i=a+b;j=b-a+1就可以求出a,b。。。
代码如下:
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
int i, j, k;
int N,M;
cin>>N>>M;
k = 2*M;
for(i=sqrt(float(k)); i>0; i--)
{
if (!(k % i))
{
j = k / i;
if (j-i+1 > 0 && i+j-1 <= 2*N)
cout<<"["<<(j-i+1)/2<<","<<(i+j-1)/2<<"]\n";
}
}
return 0;
}
时间复杂度明显降低!!!
菜鸟第一次写博客,望各位大牛多多指教!!!