1 条题解
-
0
容易将题意转化成,每次选最大的 个加 ,然后再将最大的 个减 ,重复操作 次。
显然只有最开始的 个是会被操作的,其他的贡献就是初始值的平方。只保留最大的 个,每次操作变成选最小的 个加 。
然后就变成了下面这个问题:
个数,每次给最小的 个数加 ,求操作 次后数列。
。
要总共给 个数加 ,并且每个数最多加 。容易发现,如果存在 且 加的数没有到 ,那么 不可能被加任何数,否则不满足每次给最小的加的条件。
考虑二分答案,判断是否所有小于 的数都变成 和 的最小值的代价是否 。二分要求出最大的满足条件的 。最后二分出来花了 的代价,给 个等于 的数加 就行了。
::::info[code]
#include <bits/stdc++.h> using namespace std; namespace z { #define int long long const int N = 5e5 + 5, mod = 1e9 + 7; int n, m, x, y, a[N], b[N]; void main() { ios::sync_with_stdio(false); cin.tie(nullptr);cout.tie(nullptr); cin >> n >> m >> x >> y; int ans = 0, k = x - y; for(int i = 1; i <= n; i++) cin >> a[i]; sort(a + 1, a + n + 1, greater<int>()); auto chk = [&](int t) -> bool { int sum = 0; for(int i = 1; i <= x; i++) { sum += max(0ll, min(t - a[i], m)); } return sum <= m * k; }; int l = 0, r = 2e9, t = -1; while(l <= r) { int mid = l + r >> 1; if(chk(mid)) l = mid + 1, t = mid; else r = mid - 1; } int sum = 0; for(int i = 1; i <= x; i++) { if(a[i] < t) sum += min(m, t - a[i]), a[i] = min(t, a[i] + m); } int rem = m * k - sum; for(int i = 1; i <= x && rem; i++) if(a[i] == t) a[i]++, rem--; for(int i = 1; i <= n; i++) ans += a[i] * a[i] % mod; cout << ans % mod << '\n'; } #undef int } int main() { z::main(); return 0; }::::
- 1
信息
- ID
- 1567
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 9
- 标签
- 递交数
- 17
- 已通过
- 3
- 上传者