2019-05-08组内讨论

http://acm.hdu.edu.cn/showproblem.php?pid=2058

Problem Description
Given a sequence 1,2,3,......N, your job is to calculate all the possible sub-sequences that the sum of the sub-sequence is M.

Input
Input contains multiple test cases. each case contains two integers N, M( 1 <= N, M <= 1000000000).input ends with N = M = 0.

Output
For each test case, print all the possible sub-sequence that its sum is M.The format is show in the sample below.print a blank line after each test case.

Sample Input

20 10
50 30
0 0

Sample Output

[1,4]
[10,10]

[4,8]
[6,9]
[9,11]
[30,30]


组内分析

初看这个问题,首先就想到求和公式,观察了一下,等差数列。所以采用等差数列求和公式,首项为1,公差d也为1.
这时未知数是项数n和首项a1通过for循环遍历算出每个a1和n 然后带入通项合公式符合等于m就输出。

遇到问题

1.超时
for循环时候便利到m太繁杂。
在观察别人代码发现别人对循环条件的优化是:
t=(int)sqrt(2.0*m);
for(j=t;j>=1;j--)//根据数列求和公式判断

后来经过讨论最后通过查阅网上资料和讨论。摘取这段讲解:
假设首项是1,我们代入,很容易得到n(n+1)=2m这个公式(n是项数)。 这里可以把n+1看成n,n^2=2m,
n=sqrt(2m); 也就是说项数最多的情况也只有sqrt(2m)。

这也就是说,假设M给的是10的9次方,最大的答案区间撑死也只有46000左右的长度。也就是2的10次的算术平方根

那么我们枚举1---sqrt(2m),假设是长度代入到公式中。m知道了,长度知道了,那么可以解出首项,我们知道,这个数列的每一项必定是个正整数,那么如果算出来的首项正好是个正整数,那么就是个答案,

区间就是【我们算出来的整数,整数+长度-1】输出即可。

时间复杂度为n,但是n的范围大大缩小。AC。

源代码

#include
int main()
{
    int t,n,m,i,j;//i为开始的点,j为此区间的长度
    while(~scanf("%d%d",&n,&m)&&(n||m))
    {
        t=(int)sqrt(2.0*m);
        for(j=t;j>=1;j--)//根据数列求和公式判断
        {
            int i;
            i=(2*m/j+(1-j))/2;
            if(j*(2*i+j-1)==2*m)
            {
                printf("[%d,%d]\n",i,i+j-1);
            }
        }
        printf("\n");
    }
}

总结

1.多写代码,多从算法优化上考虑花点时间


另外附上组员看书小总结:
vector动态数组
1> 定义

include

vector<类型名> 变量名;

例:vector a;

2> 常用操作

  • a[i] 访问第i个元素

  • a.empty() 判断是否为空

  • a.size() 返回元素个数

  • a.resize() 修改动态数组大小

  • a.push_back(x) 在动态数组尾部加一个元素

  • a.pop_back() 删除尾部一个元素

  • a.begin() 指向头部的迭代器(指针)

  • a.end() 指向尾部+1位置的迭代器(指针)

3> 其他操作

  • c.~vector() 销毁所有元素

  • c.insert(pos, a) 在pos处插入元素a

  • c.erase(a, b) 删除区间[a, b)内的元素

  • c.swap(c1) 交换c,c1

  • c.front() 返回第一个元素

  • c.back() 返回最后一个元素

  • c.capacity() 返回当前动态容量

  • c.max_size() 返回最大可以装的元素个数
    set集合
    头文件为set 构造方式为 set< string(类型) > name(变量名)

name.insert(sth) 插入元素
name.erase(sth) 就是删除元素
name.count(sth) 类似于一个询问 如果集合里有这个元素就返回true 否则返回false
遍历也是使用迭代器
for(set< string >::iterator i=name.begin();i!=name.end();i++)
cout<<*i<<" ";

name.clear()与vector里面的同理

map映射
头文件为map 构造方式为 map< string(类型) , string(类型) > team(变量名)

你可能感兴趣的:(2019-05-08组内讨论)