1 条题解
-
0
思路与算法
设总共有k家,自家门牌为a。所有门牌总和S=k(k+1)/2,其余门牌之和为S-a,题目再减去自家门牌的两倍,得到S-3a=n。因此枚举k,若S-n为正、能被3整除,且a=(S-n)/3不超过k,就得到合法候选。输入保证唯一解,找到后输出a和k。
当S-n>3k时,即使a取最大的k也无法满足等式,应结束枚举。此时k已大于3,而S-3k=k(k-5)/2在后续严格递增,因此不会漏掉更后面的解。
正确性说明
枚举到的每个候选均满足1<=a<=k和S-3a=n,所以重新计算其他各家门牌之和减去2a恰为n,是合法答案。任意合法解(k,a)都有S-n=3a,必满足正数、整除和边界检查;只要尚有可能存在合法a,枚举都不会提前终止,所以合法解一定被找到。题目保证唯一,输出第一个合法候选即为唯一答案。
复杂度
由n>=k(k-5)/2及n<100000,候选k小于450;循环次数O(sqrt(n)+1),每次O(1),总时间O(sqrt(n)+1),额外空间O(1),初始化O(1)。总和及差值使用long long。独立数据核验枚举了全部k<=450与自家门牌,构建完整范围解表,仅选择恰有一个解的输入。
易错点
减去的是自家门牌的三倍:先从总和删去自家一次,再减两次。输出顺序是自家门牌、总户数。不能把任意n<100000都当成合法数据;例如99999有两个解,不符合唯一性保证。本批最大合法唯一n为99997。
参考代码(C++11)
#include <iostream> using namespace std; int main() { long long n; cin >> n; for (long long count = 1;; ++count) { long long total = count * (count + 1) / 2; if (total - n > 3 * count) break; long long difference = total - n; if (difference > 0 && difference % 3 == 0 && difference / 3 <= count) { cout << difference / 3 << ' ' << count << '\n'; return 0; } } }
- 1