【题解提供者】吴立强
解法
思路
可以证明,答案必定为: 1 , 2 , 3 , . . . , k − 1 , k , g 1, 2, 3, ..., k-1, k, g 1,2,3,...,k−1,k,g。其中有 g = n − ∑ i = 1 k g = n-\sum_{i=1}^k g=n−∑i=1k 成立。
首先,基于【贪心】思想,假设当前没用过的最小的数为 x x x,当前已用的数的和为 s u m sum sum,那么如果满足 x + 1 ≤ ( n − s u m ) − x x + 1 \le (n - sum) - x x+1≤(n−sum)−x(用 x x x 这个数,且用完后剩余的数不小于后一个没用过的数),那么从字典序的定义出发,没有理由不使用 x x x,也就是说拆分的数中必定包含 x x x。
利用上述推论,我们可以确定 k k k 的取值,且同时保证了拆分出序列满足“字典序”最小。
代码展示
#include <iostream>
using namespace std;
int main() {
int T; cin >> T;
while(T --) {
int n; cin >> n;
for(int i = 1; ; i ++) { /// 从 1 开始,依次拆分
if(i + i + 1 > n) break;
cout << i << ' ';
n -= i;
}
cout << n << ' ' << endl; /// 剩下的数不支持再拆分
}
}
算法分析
程序时间复杂度为 O ( ∑ n ) O(\sum \sqrt n) O(∑n),因为 k k k 的取值必定在 n \sqrt n n 级别( ∑ i = 1 k = k × ( k + 1 ) 2 \sum_{i=1}^k=\frac{k\times(k+1)}{2} ∑i=1k=2k×(k+1))。