A
?????? //b里放最小值,其他值放c。如果最大值=最小值,則無解。
void solve() {int n; cin >> n;vi a(n); liter(x, a) cin >> x; sort(all(a));if (a[0] == a[n - 1]){print(-1); return;}vi b, c;for (int i = 0; i < sz(a); ++i){if (a[i] == a[0]){b.pb(a[i]);}else{c.pb(a[i]);}}print(sz(b), sz(c));print(b);print(c);
}
B
//答案由每個數組中第二小值構成,對于每個數組,記錄對答案的貢獻值,并找出貢獻最小的數組。貢獻最小的數組用來存儲其他數組的最小值。然后再將總的貢獻值微改即可。
void solve() {int n; cin >> n;vvi a(n);ll sum = 0;
//min_val存儲所有數組中第二小值里面最小的值。int min_val = 2e9, min_val_index = -1;int MM = 2e9;for (int i = 0; i < n; ++i){int m; cin >> m;a[i].assign(m + 2, 0);int minn = 2e9, secmin = 2e9;for (int j = 2; j <= m + 1; ++j){cin >> a[i][j];if (a[i][j] < minn){secmin = minn;minn = a[i][j];}else if (a[i][j] < secmin){secmin = a[i][j];}}a[i][0] = minn;
//如果當前數組長度為1,那么第二小值 == 最小值a[i][1] = m > 1? secmin : a[i][0];if (min_val > a[i][1]){min_val = a[i][1];min_val_index = i;}MM = min(MM, a[i][0]);sum += a[i][1];}
//以下操作等效于刪除最小的第二小值,并把其他數組中的最小值移動到這個數組中,并加上其他數組所有值移動過來以后這個數組中的最小值。if (n > 1){sum = sum - a[min_val_index][1] + MM;}else sum = a[0][0];print(sum);
}
C
思路:要讓n個數的*相應的排列的和在刪除一個最大的值后的值最大,有這樣的思路:
如果讓i*j的和最大(1<=I, j <= n),那么就讓每個i=j。然而題目要求刪除一個最大的I * j,那么求解需要將要刪除的I * j盡可能的變小,未刪除的i*j盡可能變大,在這種大前提下找到一個最優解。假設要刪除的數是n,那么讓n*i盡可能的小,就要bf嘗試各種下標i。同時,要保證其他的數盡可能的大,但是不能大過n*I,就將i后面的數從n-1逆序排列,升序i*逆序n – 1開始的排列,可能會滿足最大的數盡可能小,而其他的數每個數都得到一定程度的變大。
測試:輸入10
1 2 3 4 5 6 10 9 8 7
1 4 9 16 25 36 49 64 81 100 升序排列I = j各個位置的和,最后需要刪除100,后4位是49+75+81=194
1 4 9 16 25 36 70 72 72 70????? 將n 放在I = 7的位置,最后需要刪除72,后4位是70+72+70=212.
可以發現,對于這樣的一個規則來說,可以找到一個下標起點,用來存放從n開始逆序排列的一個序列,會讓這個序列*對應下標的值盡可能的接近,比如上面的70, 72, 72, 70,以至于刪除一個最大的值后,其余的值加起來的和的貢獻>升序排列刪除最大值后的和的貢獻。
?
void solve() {int n; cin >> n;ll sum = 0;auto cal = [&n](vi& a){ll result = 0;int in = 0;for (int i = 1; i <= n; ++i){result += 1ll * a[i] * i;if (a[in] * in < a[i] * i) in = i;}result -= a[in] * in;return result;};ll result = 0;vi a(n + 1);for (int i = 1; i <= n; ++i){a[i] = n;for (int j = 1; j < i; ++j) a[j] = j;for (int j = i + 1; j <= n; ++j) a[j] = a[j - 1] - 1;result = max(result, cal(a));}print(result);
}
總結:關鍵點在于盡快找到:將最大最盡可能的變小,其他的值盡可能變大的點->推理出從某個下標讓n開始降序排列,然后暴力求解。
D
放個TLE代碼
struct pts{int l, r, a, b;void read() {cin >> l >> r >> a >> b;}bl operator <(cst pts& x){return b < x.b;}
};void solve() {int n; cin >> n;vector<pts> a (n);liter(x, a) x.read();sort(all(a));int q; cin >> q;while (q--){int pos; cin >> pos;liter(x, a){if (pos >= x.l && pos <= x.r) pos = max(pos, x.b);}print(pos, ' ');}newline;
}