USACO 1.4 Arithmetic Progressions

这题略有点繁琐啊- - 先构造出所有的双平方数字在a数组里,p[i]表示i这个数字,在a数组的下标

穷举公差……但是公差其实是有范围的(小优化一下)

直接在双平方数字基础上穷举,用公差计算出的新的数字,在O(1)时间内判断出,是否还是双平方数…… 然后倒着算一下就行了。 程序自我感觉还算短……我没啥剪枝的说,下次想想。

这个很慢了……别人都0.4秒

Executing...
   Test 1: TEST OK [0.003 secs, 5932 KB]
   Test 2: TEST OK [0.005 secs, 5932 KB]
   Test 3: TEST OK [0.003 secs, 5932 KB]
   Test 4: TEST OK [0.005 secs, 5932 KB]
   Test 5: TEST OK [0.038 secs, 5932 KB]
   Test 6: TEST OK [0.138 secs, 5932 KB]
   Test 7: TEST OK [1.245 secs, 5932 KB]
   Test 8: TEST OK [2.595 secs, 5932 KB]
   Test 9: TEST OK [2.314 secs, 5932 KB]


/*
TASK:ariprog
LANG:C++
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
int N, M;

bool v[125001]={0};
int p[125001];  //这个数字,在a中的数组下标
int a[125001], t;//保存双平方数 从小到大排序
int count[125001]={0},ct(0);

typedef std::pair<int,int> PII;
PII Q[125001];

bool cmp(PII A , PII B)
{
	if (A.second != B.second)	return A.second < B.second;
	return A.first < B.first;
}

int main()
{
	freopen("ariprog.in", "r", stdin);
	freopen("ariprog.out", "w", stdout);
	scanf("%d%d", &N, &M);	
	for (int i = 0; i <= M; ++ i)
		for (int j = 0; j <= M; ++ j)	v[i * i + j * j] = true;
	for (int i = 0; i <= M * M * 2; ++ i)	
		if (v[i])
		{
			a[++ t] = i;
			p[i] = t;	
		}
	for (int i = 1; i <= M * M * 2/ (N - 1); ++ i) //穷举公差
	{
		memset(count, 0, sizeof(count));//所有元素为结束点,公差为i的个数
		for (int j = t; j >= 0; -- j)	 //穷举起点位置的元素下标 
		{
			if (count[j])	continue; //如果j号元素已经穷举过了,那么直接跳过即可
			int now(a[j]);
#define will (now - i)
			for (count[j] = 1; v[will] && will >= 0; now = will)
			{
				count[p[will]] = count[p[now]] + 1;
				if (count[p[will]] >= N)	Q[++ct] = std::make_pair<int, int>(will, i);
			}
		}
	}
	std::sort(Q + 1, Q + 1 + ct, cmp);
	for (int i = 1; i <= ct; ++ i)	printf("%d %d\n",Q[i].first, Q[i].second);
	if (!ct)	printf("NONE\n");
	return 0;
}


你可能感兴趣的:(USACO 1.4 Arithmetic Progressions)