[AGC059D] Distinct Elements on Subsegments
Genius_Star · · 题解
或许更好的阅读体验。
这题牛逼完了。
思路:
考虑显然有相邻两个满足
那么如果
于是首先你可以得到一些
具体的,把每个数
于是对于一个固定的
显然最优的一定是
限制考虑如何构造
-
如果
b_i = b_{i + 1} = k ,说明这k 个数互不相同,那么一定有r_i = l_{i + k} = 1 。 -
否则,你发现赋值为
r_i = l_{i + k} = 0 一定不劣;先把外面能匹配的0 全部匹配上,因为b_i \ne k ,所以[i, i + k - 1] 中一定存在两个相同的数且互为前驱后继,设为a_u = a_v ,那么r_u = 0, l_v = 0 ,且一定互相匹配(根据前面的形式),此时修改成(v, i), (i + k, u) 匹配是显然合法的,于是不劣;更优的是,相当于给中间不存在匹配0 多了一些机会。
于是按照上面的分讨把所有
现在得到了满足限制的
-
如果
l_i = 1 ,那么随便拿一个和前面k - 1 位不同的数即可。 -
否则
l_i = 0 ,其和一个r_j = 0 是匹配的,令a_i \gets a_j 即可。
时间复杂度为
完整代码:
#include<bits/stdc++.h>
#define fi first
#define se second
#define lowbit(x) x & (-x)
#define popcnt(x) __builtin_popcountll(x)
typedef long long ll;
using namespace std;
const int N = 4e5 + 10;
inline ll read(){
ll x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9'){
if(c == '-')
f = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
return x * f;
}
inline void write(ll x){
if(x < 0){
putchar('-');
x = -x;
}
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
int T, n, k;
int a[N], b[N], l[N], r[N];
inline void solve(){
n = read(), k = read();
for(int i = 1; i <= n; ++i)
b[i] = read();
for(int i = 1; i <= n + k - 1; ++i)
l[i] = r[i] = -1;
for(int i = 1; i < n; ++i){ // b[i + 1] = b[i] + l[i + k] - r[i]
if(abs(b[i] - b[i + 1]) > 1){
puts("NO");
return ;
}
if(b[i] == b[i + 1]){
if(b[i] == k)
r[i] = l[i + k] = 1;
else
r[i] = l[i + k] = 0;
}
else{
if(b[i + 1] > b[i]){
l[i + k] = 1;
r[i] = 0;
}
else{
l[i + k] = 0;
r[i] = 1;
}
}
}
for(int i = 1; i <= k; ++i){
if(l[i] == -1){
if(b[1])
l[i] = 1, --b[1];
else
l[i] = 0;
}
else
b[1] -= l[i];
}
for(int i = n + k - 1; i >= 0; --i){
if(r[i] == -1){
if(b[n])
r[i] = 1, --b[n];
else
r[i] = 0;
}
else
b[n] -= r[i];
}
// for(int i = 1; i <= n + k - 1; ++i){
// cerr << l[i] << ' ';
// }
// cerr << '\n';
// for(int i = 1; i <= n + k - 1; ++i){
// cerr << r[i] << ' ';
// }
// cerr << '\n';
int s0 = 0, s1 = 0;
for(int i = 1; i <= n + k - 1; ++i)
s0 += (!l[i]), s1 += (!r[i]);
if(s0 != s1){
puts("NO");
return ;
}
int cnt = 0;
queue<int> q;
for(int i = 1; i <= n + k - 1; ++i){
if(l[i] == 1)
a[i] = ++cnt;
else{
if(q.empty()){
puts("NO");
return ;
}
a[i] = a[q.front()];
q.pop();
}
if(!r[i])
q.push(i);
}
puts("YES");
for(int i = 1; i <= n + k - 1; ++i){
write(a[i]);
putchar(' ');
}
putchar('\n');
}
int main(){
T = read();
while(T--)
solve();
return 0;
}