这题略有点繁琐啊- - 先构造出所有的双平方数字在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; }