事实上,只有一个桶的时候不需要什么 Gale-Ryser 定理。
设 为
最终变成的数,那么需要满足如下限制:
- 设 ,那么
,且 。
是的,在只有一个箱子的时候只用考虑有没有数大于总和除以箱子大小即可。
然后发现两条性质:
- 将 排序后, 也单调递增,要不然调整之后不劣。
- 只需考虑
的解,这个证明比较巧妙,我们对
序列取一个特征值 ,在最优解中,我们只考虑 最小的那个。如果此时 中存在 ,那么将 减
, 加
,原来的所有限制仍然满足,代价也不变,同时 变小了。所以我们不需要考虑存在 的解。
综上,我们只需考虑形如 的 。限制 与 都可以提供一个 的下界。设最后 的下界为 ,我们在 中检查有没有 可以使得 即可。
时间复杂度 或 ,不是重点。本题重点在于充要条件的观察。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include <bits/stdc++.h> using namespace std; const int N = 3e5 + 5; int n,m,a[N]; long long sa; long long X; inline long long Sx(long long x) { return 1ll * x * n + 1ll * n * (n - 1) / 2;} inline long long ceil_div(long long x,long long y) { if(y < 0) y = -y,x = -x; if(x <= 0) return x / y; return (x - 1) / y + 1; } int main() { cin >> n >> m; for(int i = 0;i < n;i++) cin >> a[i],sa += a[i]; sort(a,a + n); X = 0; for(int i = 0;i < n;i++) { X = max<long long>(X,a[i] - i); long long val = 1ll * m * (a[i] - i) - sa + 1ll * n * (n - 1) / 2; X = max<long long>(X,ceil_div(-val,n - m)); } for(int i = 0;i <= n;i++) if((Sx(X + i) - sa) % m == 0) { printf("%lld\n",(Sx(X + i) - sa) / m);return 0;} printf("-1\n"); return 0; }
|