HOJ 2058 The sum problem
HOJ 2058 The sum problem
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]
滑动窗口
本来觉得这题没难度,就滑动窗口直接做了。
#include "iostream"
#include "cstdio"
using namespace std;
__int32 min(__int32 x, __int32 y) {
return x > y ? y : x;
}
int main() {
__int32 N,M;
__int32 left, right,sum;
while (scanf("%d %d", &N,&M) != EOF) {
if (N == 0 && M == 0)break;
left = right = 1;
sum = 1;
while (right <= min(N,M)) {
if (sum < M) {
sum += ++right;
continue;
}
if (sum == M) {
printf("[%d,%d]\n", left, right);
}
if (sum >= M) {
sum -= left++;
continue;
}
}
printf("\n");
}
return 0;
}
但是当数据量过大,还是会挂。
优化
看了别人的代码,优化了一下
题目是要求等差数列[1,N]中的某一段累加等于M,根据等差数列求和公式,也就是说我们要找到\(len\times a_1+\frac{len(len-1)d}{2}==M\)。(len是等差数列中的n,因为题中已有一个N,避免混淆。\(len=结束位置-起始位置+1\))
所以题目转换成了,我们找到一个起始位置和一个结束位置,如果满足上面的公式,则输出这两个位置。
但如果硬找起始位置和结束位置,我们发现还是要很高的复杂度,我们从长度入手,发现把上面的公式变化形态,得到这样的公式:
把这个数列所有可能的长度遍历一遍,就能求出\(a_1\)并且\(a_n=a_1\times len + len -1\)
#include "iostream"
#include "cstdio"
using namespace std;
int main() {
int N,M,len,maxLen,t;
while (scanf("%d %d", &N,&M) != EOF) {
if (N == 0 && M == 0)break;
maxLen = sqrt(M*2);
for (len = maxLen; len > 0; len--) {
t = M - len * (len - 1) / 2;
if (t % len == 0)
printf("[%d,%d]\n", t / len, t / len + len -1);
}
printf("\n");
}
return 0;
}