https://nanti.jisuanke.com/t/26
- 时间限制 2000ms
- 空间限制 65536K
一个等差数列是一个能表示成 a, a+b, a+2b,..., a+nb (n=0,1,2,3,...的数列。
在这个问题中 a 是一个非负的整数,b 是正整数。写一个程序来找出在双平方数集合(双平方数集合是所有能表示成 p^2+q^2 的数的集合) S 中长度为 n 的等差数列。
输入格式
输入包括两行,第一行为 N(3≤N≤25)要找的等差数列的长度。第二行是找到的双平方数 pp 和 qq 的上界 M(0≤p,q≤M)。
输出格式
输出一行或者多行,如果没有找到数列,输出NONE
。否则输出一个整数对a b
(这些行应该先按 b 排序再按 a 排序)
样例输入
5
7
样例输出
1 4
37 4
2 8
29 8
1 12
5 12
13 12
17 12
5 20
2 24
解题思路
这个题目很简单,就是采用暴力求解,枚举所有可能的首项和公差,关键是通过剪枝,降低运行时间。
首先,我们用一个数组vis[i]记录i是否是双平方数;同时为了加速,用sq[]有序记录所有的双平方数(除去中间的空位置,对付大数据时很有用)。然后就很简单了,我们通过枚举首项和公差,并连续算N-1个数看是否都在数组vis[]中。
注意,要求按b排序,再按a二次排序。
提示:利用约束a+(n-1)*b <= sq[max]来剪枝。
#include <iostream>
#include <algorithm>
using namespace std;
int vis[150010], sq[150010];
struct node
{
int a,b;
}s[150010];
int cmp(node x, node y)
{
if (x.b != y.b)
return x.b < y.b;
return x.a < y.a;
}
int main()
{
int a, ans, num, n, m, k;
while (cin >> n >> m)
{
num = a = 0;
for (int p = 0; p <= m; p++)
for (int q = p; q <= m; q++)
if (!vis[p * p + q * q])
vis[sq[a++] = p * p + q * q] = 1;
for (int i = 0; i < a; i++)
{
for (int j = 1; j <= 2 * m * m; j++)
{
if (sq[i] + (n - 1) * j > 2 * m * m)
break;
for (k = 1; k < n; k++)
if (!vis[sq[i] + k * j])
break;
if (k != n)
continue;
s[num].a = sq[i];
s[num++].b = j;
}
}
if (!num)
{
cout << "NONE\n";
continue;
}
sort(s, s + num, cmp);
for (int i = 0; i < num; i++)
cout << s[i].a << " " << s[i].b << endl;
}
return 0;
}