Konstruktiv Əyləncə#11839

Konstruktiv Əyləncə (Həll təhlili)

Problem Author:

Hasan Saleh (MathModel)

Prepared by:

Hasan Saleh (MathModel)

Edited by:

Kostiantyn Denysov

Note that the expression \sum_{1 \le i < j \le n} |a_i - a_j| does not depend on the order of elements in the array. Therefore, without loss of generality, we can assume that the array is sorted in non-decreasing order:

a_1 \le a_2 \le \dots \le a_n

This assumption allows us to remove absolute values and rewrite the expression more conveniently:

\sum_{1 \le i < j \le n} (a_j - a_i)

Let us analyze how each element contributes to the total sum:

\sum_{1 \le i < j \le n} (a_j - a_i)

We can group the terms by indices. Fix some index . The element a_i appears:

  • as a subtrahend (with a ) in all pairs where i < j . There are n - i such pairs.

  • as a minuend (with a ) in all pairs where j < i . There are i - 1 such pairs.

Therefore, the total contribution of a_i to the sum is:

a_i \cdot [(i - 1) - (n - i)] = a_i \cdot (2i - n - 1)

Summing over all , we obtain:

\sum_{i=1}^n a_i \cdot (2i - n - 1)

This gives us an alternative way to compute the total sum of absolute differences for a sorted array.

Recall that we have assumed the array is sorted in non-decreasing order:

a_1 \le a_2 \le \dots \le a_n

To ensure this property holds, we define the array in terms of non-negative increments. Specifically, we let:

a_1 = x_1, \quad a_2 = a_1 + x_2, \quad a_3 = a_2 + x_3, \quad \dots, \quad a_n = a_{n-1} + x_n,

where x_i \ge 0 for all . That is,

a_i = \sum_{j=1}^{i} x_j.

This representation guarantees that a_1 \le a_2 \le \dots \le a_n, since each subsequent value is obtained by adding a non-negative quantity.

We now substitute this representation into our earlier expression for the total sum of absolute differences:

\sum_{i=1}^n a_i \cdot (2i - n - 1) = \sum_{i=1}^n \left( \sum_{j=1}^{i} x_j \right) \cdot (2i - n - 1).

Exchanging the order of summation:

= \sum_{j=1}^n x_j \cdot \left( \sum_{i=j}^n (2i - n - 1) \right).

This gives us a linear expression in terms of the variables x_j, which we can now manipulate to achieve any desired total value of the sum.

Using the increment-based representation of the array, we obtain the following formula for the total sum of pairwise absolute differences:

\sum_{1 \le i < j \le n} |a_i - a_j| = \sum_{j=1}^n x_j \cdot (n - j + 1)(j - 1),

where x_1, x_2, \dots, x_n are non-negative integers such that

a_i = \sum_{k=1}^i x_k.

This formula allows us to construct an array with any desired value of the sum by appropriately choosing the values of x_j.

Let us denote the coefficient of x_j as:

w_j = (j - 1)(n - j + 1).

Our goal is to choose non-negative integers x_j such that:

\sum_{j=1}^n x_j \cdot w_j = k.

This is equivalent to an unbounded knapsack problem: we are given item weights w_1, w_2, \dots, w_n, and we may take each item any number of times (including zero), with the goal of reaching total weight exactly .

Solving this version of the knapsack problem gives us a valid set of increments x_j, which in turn defines a non-decreasing array a_1, a_2, \dots, a_n satisfying the required condition.

Since our goal is to achieve total weight exactly , we are not interested in any item whose weight exceeds . That is, for any such that:

w_j = (j - 1)(n - j + 1) > k,

we can safely ignore the corresponding variable x_j.

Furthermore, we observe that for a fixed , the number of indices for which w_j \le k is relatively small. Indeed, solving the inequality:

(j - 1)(n - j + 1) \le k

we find that there are only O(\min(n, k / n)) such values of .

This significantly reduces the number of distinct weights we need to consider, which allows us to solve the unbounded knapsack problem efficiently even when is large.

\min(n, \frac{k}{n}).

This quantity is maximized when n = \sqrt{k}, so we conclude that:

\min(n, \frac{k}{n}) \le \sqrt{k}.

Therefore, the number of item types we need to consider in our unbounded knapsack problem is at most O(\sqrt{k}).

If we implement the standard dynamic programming solution to the unbounded knapsack problem over these weights and target value , it runs in time:

O(k \cdot \sqrt{k}).

Although the theoretical time complexity of the unbounded knapsack solution is O(k \cdot \sqrt{k}), in practice it performs much faster.

Empirical observations show that for all values of n \le 10^4, it is sufficient to consider only the first weights w_j = (j - 1)(n - j + 1) to be able to construct any possible target sum within the allowed range.

Moreover, standard optimizations for the unbounded knapsack problem — such as using early stopping, avoiding redundant updates — already yield significant speed-ups.

Even without using advanced techniques such as bitsets, the algorithm runs much faster than the pessimistic bound of O(k \cdot \sqrt{k}) in real scenarios.

//#pragma GCC optimize("Ofast", "unroll-loops")
//#pragma GCC target("sse", "sse2", "sse3", "ssse3", "sse4")

#include <bits/stdc++.h>

#define all(a) a.begin(),a.end()
#define len(a) (int)(a.size())
#define mp make_pair
#define pb push_back
#define fi first
#define se second

using namespace std;

typedef pair<int, int> pii;
typedef long long ll;
typedef long double ld;
template<class T>
using vec = vector<T>;

template<typename T>
bool umin(T &a, T b) {
    if (b < a) {
        a = b;
        return true;
    }
    return false;
}
template<typename T>
bool umax(T &a, T b) {
    if (a < b) {
        a = b;
        return true;
    }
    return false;
}

#ifdef KoRoVa
#define DEBUG for (bool _FLAG = true; _FLAG; _FLAG = false)
#define LOG(...) print(#__VA_ARGS__" ::", __VA_ARGS__) << endl
template <class ...Ts> auto &print(Ts ...ts) { return ((cerr << ts << " "), ...); }
#else
#define DEBUG while (false)
#define LOG(...)
#endif

const int max_n = 6e6 + 11, inf = 1000111222;



const int max_k = 1e6 + 11;

int id[max_k];

void test_case() {
    int n, k;
    cin >> n >> k;
    vector <int> have(k + 1);
    have[0] = 1;


    for (int i = 1; i < n && !have[k]; i++) {
        int c = i * (n - i);
        if (c > k) {
            break;
        }
        if (have[c]) { // no need to update if we can make such sum already
            continue;
        }
        for (int j = c; j <= k; j++) {
            if (have[j - c]) {
                if (!have[j]) {
                    have[j] = true;
                    id[j] = i;
                }
            }
        }
    }
    assert(have[k]);
    vector <int> add(n);
    while (k) {
        int i = id[k];
        int c = i * (n - i);
        k -= c;
        add[i] += 1;
    }
    vector <int> ans(n, 1);
    for (int i = 1; i < n; i++) {
        ans[i] = ans[i - 1] + add[i];
    }
    for (auto &i : ans) {
        cout << i << ' ';
    }
    cout << '\n';
}



int main() {
//    freopen("input.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);

    ios_base::sync_with_stdio(0);
    cin.tie(0);

    int t = 1;

    cin >> t;

    while (t--) test_case();

    return 0;
}

/*
KoRoVa!
*/