CodeForces673 Div.2 D

CodeForces673 Div.2 D - Make Them Equal 思维,构造

题意

给定正数数组(a),长度为(n)

要求在(3n)次操作内使数组的值都相等。

操作描述如下:

任何操作结束后必须保证所有元素非负

[1.选择i,j,x.其中1leq i leq jleq n.0leq xle 10^9\ 2.使得a_i -= x * i,a_j += x * i ]

[0 leq k leq 3n\ 1leq a_i leq 10^5 ]

分析

贪心方案如下:

  • (2-n)的数组变为(i)的倍数
  • 把这些数加给(a_1)
  • (a_1)分配给其他数

难点在于如何使每次操作后元素保持非负数,并且使得元素是(i)的倍数。

不妨令

[a_1 = a_1 - (i - a_i \% i)\ a_i = a_i + (i - a_i \% i) ]

容易通过数学归纳法证明这个构造方法。

代码

int a[10005];

struct S {
    int i, j;
    ll x;
    S(int _i, int _j, ll _x) {
        i = _i;
        j = _j;
        x = _x;
    }
};

void go(int x, int y, int val) {
    a[x] -= x * val;
    a[y] += x * val;
}

void solve() {
    int n = readint();
    ll sum = 0;
    for (int i = 1; i <= n; i++)
        a[i] = readint(), sum += a[i];
    if (sum % n) {
        puts("-1");
        return;
    }
    ll num = sum / n;
    vector<S> res;
    for (int i = 2; i <= n; i++) {
        if (a[i] % i) {
            res.push_back(S(1, i, i - a[i] % i));
            go(1, i, i - a[i] % i);
        }
        res.push_back(S(i, 1, a[i] / i));
        go(i, 1, a[i] / i);
    }
    for (int i = 2; i <= n; i++) {
        res.push_back(S(1, i, num));
        go(1, i, num);
    }
    cout << res.size() << '
';
    for (int i = 0; i < res.size(); i++)
        cout << res[i].i << ' ' << res[i].j << ' ' << res[i].x << '
';
}


int main() {
    int T = readint();
    while (T--) solve();
}
原文地址:https://www.cnblogs.com/hznumqf/p/13756061.html