纪念邮票问题

纪念邮票
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;
}


时间复杂度明显降低!!!



菜鸟第一次写博客,望各位大牛多多指教!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值