考虑判断有无解。把序列分成 \(c = \left\lceil\frac{len}{k}\right\rceil\) 段,则 \(\forall a_i \le c\) 且 \(\sum\limits_{i=1}^n [a_i = c] \le ((len - 1) \bmod k) + 1\)。
必要性显然。充分性可以考虑直接构造,不难证明。
考虑如何构造字典序最小。贪心,如果当前不得不填 \(a_i = c\) 的数了,那么找到最小的并且能填的填;否则就直接找最小然后填即可。
感觉挺神奇的贪心题,怎么想到的!
code
// Problem: E - K Different Values
// Contest: AtCoder - Daiwa Securities Co. Ltd. Programming Contest 2021(AtCoder Regular Contest 128)
// URL: https://atcoder.jp/contests/arc128/tasks/arc128_e
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 200100;
int n, m, len, a[maxn], b[maxn], c[maxn];
void solve() {
scanf("%d%d", &n, &m);
mems(c, -0x3f);
int cnt = 0;
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
len += a[i];
}
for (int i = 1; i <= n; ++i) {
if (a[i] > (len + m - 1) / m) {
puts("-1");
return;
}
cnt += (a[i] == (len + m - 1) / m);
}
if (cnt > (len - 1) % m + 1) {
puts("-1");
return;
}
for (int i = 1; i <= len; ++i) {
cnt = 0;
for (int j = 1; j <= n; ++j) {
cnt += (a[j] == (len + m - i) / m);
}
if (cnt == (len - i) % m + 1) {
for (int j = 1; j <= n; ++j) {
if (c[j] + m <= i && a[j] == (len + m - i) / m) {
printf("%d ", j);
--a[j];
c[j] = i;
break;
}
}
} else {
for (int j = 1; j <= n; ++j) {
if (c[j] + m <= i && a[j]) {
printf("%d ", j);
--a[j];
c[j] = i;
break;
}
}
}
}
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}
- Different AtCoder Regular Contest Valuesdifferent atcoder regular contest atcoder regular contest 165 minimization atcoder regular contest atcoder regular contest 166 atcoder regular contest degree atcoder regular contest sliding atcoder regular contest 167 atcoder regular contest 164 atcoder regular contest builder subsegments atcoder regular contest