题目:传送门
题意:让你构造一个长度为 n 的序列,使得 1 < a1 < a2 < ...... < an <= 1e9,且满足 1 < i < j < k <= n && a[ i ] + a[ j ] = a[ k ] 这样的三元组恰好只有 m 个,如果不能构造输出 -1.
思路:
首先,让所有 a[ i ] = i,这样的话,三元组共有 (i - 1) / 2 (i 从 1 到 n) 累加起来 个,且这个是最多的个数。那如果 m 大于累加得到的答案, 那么就不可能构造得出。(比赛的时候发现了这个规律)。
这样的话,如果 m 恰巧等于某一段前缀和,那答案就很显然了,现在需要解决的是 m 不等于某一段前缀和的情况。这里需要发现另一个规律。
你前 j 个都让 a[ j ] = j,然后你 a[ i ] 如果等于 i,那么会增加 (i - 1) / 2 组三元组,然后你会发现,你 a[ i ] = i + 2,你会增加 ( i - 3 ) / 2 组三元组,也就是说,你 i 每增加 2,你增加的三元组个数就减少 1,那就好办了,直接枚举某一段前缀和,然后构造出来,后面的就填那些不可能和前面的构成三元组的数就行了。
#include <bits/stdc++.h> #define LL long long #define mem(i, j) memset(i, j, sizeof(i)) #define rep(i, j, k) for(int i = j; i <= k; i++) #define dep(i, j, k) for(int i = k; i >= j; i--) #define pb push_back #define make make_pair #define INF INT_MAX #define inf LLONG_MAX #define PI acos(-1) using namespace std; const int N = 1e6 + 5; int a[N]; void solve() { int n, m; scanf("%d %d", &n, &m); int res = 0; rep(i, 1, n) { res += (i - 1) / 2; if(res >= m) { rep(j, 1, i - 1) printf("%d ", j); printf("%d ", i + (res - m) * 2); int now = 500000000; rep(j, i + 1, n) printf("%d ", now), now += 5000; return ; } } puts("-1"); return ; } int main() { // int _; scanf("%d", &_); // // while(_--) solve(); solve(); return 0; }