An arithmetic progression is a sequence of the form a, a+b, a+2b, ..., a+nb where n=0,1,2,3,... . For this problem, a is a non-negative integer and b is a positive integer.
Write a program that finds all arithmetic progressions of length n in the set S of bisquares. The set of bisquares is defined as the set of all integers of the form p2 + q2 (where p and q are non-negative integers).
TIME LIMIT: 5 secs
PROGRAM NAME: ariprog
INPUT FORMAT
Line 1: | N (3 <= N <= 25), the length of progressions for which to search |
Line 2: | M (1 <= M <= 250), an upper bound to limit the search to the bisquares with 0 <= p,q <= M. |
SAMPLE INPUT (file ariprog.in)
5 7
OUTPUT FORMAT
If no sequence is found, a singe line reading `NONE'. Otherwise, output one or more lines, each with two integers: the first element in a found sequence and the difference between consecutive elements in the same sequence. The lines should be ordered with smallest-difference sequences first and smallest starting number within those sequences first.
There will be no more than 10,000 sequences.
SAMPLE OUTPUT (file ariprog.out)
1 4 37 4 2 8 29 8 1 12 5 12 13 12 17 12 5 20 2 24
题目是明显的暴搜,5s的时间,我看时间还是挺多的,就尝试着自己按最暴力最原始的方式来完成这题,思路是这样的:根据n m大概确定a b的范围,对a b循环搜索,对每一个a b,检验是否是双平方数,然后用vector存起来,最后排序输出。结果可想而知,超时。
TASK: ariprog LANG: C++ Compiling... Compile: OK Executing... Test 1: TEST OK [0.000 secs, 3184 KB] Test 2: TEST OK [0.000 secs, 3184 KB] Test 3: TEST OK [0.000 secs, 3052 KB] Test 4: TEST OK [0.022 secs, 3184 KB] Test 5: TEST OK [3.650 secs, 3184 KB]
> Run 6: Execution error: Your program (`ariprog') used more than the allotted runtime of 5 seconds (it ended or was stopped at 5.378 seconds) when presented with test case 6. It used 3180 KB of memory. ------ Data for Run 6 ------ 18 100 ---------------------------- |
Test 6: RUNTIME 5.378>5 (3180 KB)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
struct arip
{
int a, b;
arip(int a1, int b1):a(a1),b(b1){}
};
int n, m, i, j, a, b, m2, temp;
bool found = 0;
int square[250+1] = {0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576,
625, 676, 729, 784, 841, 900, 961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209, 2304, 2401,
2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, 3969, 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476,
5625, 5776, 5929, 6084, 6241, 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, 9216, 9409, 9604, 9801,
10000, 10201, 10404, 10609, 10816, 11025, 11236, 11449, 11664, 11881, 12100, 12321, 12544, 12769, 12996, 13225, 13456, 13689, 13924, 14161, 14400, 14641, 14884, 15129, 15376,
15625, 15876, 16129, 16384, 16641, 16900, 17161, 17424, 17689, 17956, 18225, 18496, 18769, 19044, 19321, 19600, 19881, 20164, 20449, 20736, 21025, 21316, 21609, 21904, 22201,
22500, 22801, 23104, 23409, 23716, 24025, 24336, 24649, 24964, 25281, 25600, 25921, 26244, 26569, 26896, 27225, 27556, 27889, 28224, 28561, 28900, 29241, 29584, 29929, 30276,
30625, 30976, 31329, 31684, 32041, 32400, 32761, 33124, 33489, 33856, 34225, 34596, 34969, 35344, 35721, 36100, 36481, 36864, 37249, 37636, 38025, 38416, 38809, 39204, 39601,
40000, 40401, 40804, 41209, 41616, 42025, 42436, 42849, 43264, 43681, 44100, 44521, 44944, 45369, 45796, 46225, 46656, 47089, 47524, 47961, 48400, 48841, 49284, 49729, 50176,
50625, 51076, 51529, 51984, 52441, 52900, 53361, 53824, 54289, 54756, 55225, 55696, 56169, 56644, 57121, 57600, 58081, 58564, 59049, 59536, 60025, 60516, 61009, 61504, 62001,
62500};
bool check_bisquare() {
for(i = 0; i <= n-1; i++) {
found = 0;
for(j = 0; temp = a+i*b, square[j] <= temp; j++)
if((square[j] <= m2) && (temp - square[j] <= m2) && binary_search(square, square+251 ,temp - square[j])) {
found = 1;
break;
}
if(found == 0)
return false;
}
return true;
}
bool cmp(const arip& a1, const arip& a2) {
return a1.b < a2.b ? 1 : (a1.b == a2.b ? a1.a < a2.a : 0);
}
int main()
{
freopen("ariprog.in", "r", stdin);
freopen("ariprog.out", "w", stdout);
vector<arip> vec;
scanf("%d%d", &n, &m);
m2 = m*m;
for(b = 1; b <= (m2<<2)/(n-1); b++)
for(a = 0; a <= (m2<<2)-(n-1)*b; a++)
if(check_bisquare())
vec.push_back(arip(a, b));
if(vec.size() == 0) {
printf("NONE\n");
}else {
sort(vec.begin(), vec.end(), cmp);
for(vector<arip>::iterator idx = vec.begin(); idx != vec.end(); idx++)
printf("%d %d\n", idx->a, idx->b);
}
return 0;
}
上网看了一下别人的思路,原来是应该强搜双平方数,而不是强搜a b,双平方数最多有250*250*2 = 125000,可以接受,在双平方数中先强搜确定a,再根据a+nb<2*m*m确定b的强搜范围,对每个a b判断所有的序列是否属于双平方数。ACM虽然接触了一下,但仅仅限于选修课上。个人感觉每道题都不太会,看到题目只会强搜,深一点的算法题就不会了。但听了一位师兄说,只要坚持搞ACM一个月,一定会有感觉的。正在努力当中。。。
经过一天的努力,参考了别人的代码,终于通过了,运行最慢才0.302s<<5s,庆祝一下!!
/*
LANG: C++
TASK: ariprog
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
struct arip
{
int a, b;
arip(int a1, int b1):a(a1),b(b1){}
};
int n, m, i, j, a, b, k, cnt = 0, temp = 0, m2;
bool square_bit[125000+10] = {false};
int square_num[125000+10] = {0};
vector<arip> vec;
void db() {
for(int i = 0; i < cnt; i++)
cout<<square_num[i]<<endl;
}
void make() {
for(i = 0; i <= m; i++)
for(j = 0; j <= m; j++) {
temp = i*i+j*j;
if(square_bit[temp] == 0) {
square_bit[temp] = true;
square_num[cnt++] = temp;
}
}
sort(square_num, square_num+cnt);
m2 = m*m;
}
bool check_bisquare(int a, int b) {
for(k = 0; k <= n-1; k++)
if(square_bit[a+k*b] == 0)
return false;
return true;
}
void cal_ab() {
for(i = 0,a = 0; i < cnt; i++, a = square_num[i])
for(j = i+1, b = square_num[j]-square_num[i]; a+(n-1)*b <= 2*m2 && j < cnt; j++, b = square_num[j]-square_num[i]) {
//cout<<a<<" ,"<<b<<endl;
if(check_bisquare(a, b))
vec.push_back(arip(a, b));
}
}
bool cmp(const arip& a1, const arip& a2) {
return a1.b < a2.b ? 1 : (a1.b == a2.b ? a1.a < a2.a : 0);
}
int main()
{
freopen("ariprog.in", "r", stdin);
freopen("ariprog.out", "w", stdout);
scanf("%d%d", &n, &m);
make();
//db();
cal_ab();
if(vec.size() == 0) {
printf("NONE\n");
}else {
sort(vec.begin(), vec.end(), cmp);
for(vector<arip>::iterator idx = vec.begin(); idx != vec.end(); idx++)
printf("%d %d\n", idx->a, idx->b);
}
return 0;
}
前后相差这么远,可以看到不是强搜就是简单的,从什么角度搜用什么来保存状态怎样剪枝,这些都影响到程序的效率。
这次学会了空间换时间,下标作为变量保存状态。