有一个数组 ,它的前缀和数组是 , 数组的前缀最大值为数组 。
用二进制字符串表示数组 的哪些值是确定的,0 代表待定 1 代表确定,给定完整的数组 ,问是否存在可能的 数组?
首先能想到, 数组一定是单调不降的,而一旦变化只能是增加。令值发生变化的下标为 ,则 。
其次 ,所以对于确定的 ,对应的 的差值是确定的。所以 什么时候可以自由选择呢?当 为不确定的时候。
我们可以按照这样的特征将序列划分为若干个段,由 0 开头,后面跟着若干个 1(可以没有 1)。
对于每个 段,只有 是可选的,一旦 确定,则后面所有的 也确定了,所以我们可以给出 ,令 ,特别地,,满足:
所以 ,我们令 。
如果 区间内没有出现任何 出现变化的节点,那么我们就可以令 。
如果出现了若干个 变化的点,那么此时 ,此时就会算出一个固定的 ,如果有几个不同固定的 ,则无解。若最后这个固定的 ,也无解。
注意第一个位置属于 变化的点,所以 会由 决定一次,还会由 决定一次,如果这两个值冲突,也无解。
注意要开 long long。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
int n;
string s;
cin >> n;
cin >> s;
s = ' ' + s;
vector<ll> a(n + 2, 0);
vector<ll> b(n + 1, 0), c(n + 1);
bool ok = true;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
cin >> c[i];
}
int i = 1;
while (i <= n) {
if (i == 1 || s[i] == '0') {
ll delta = 0;
ll M = 4e18;
int idx = i;
ll L = 0;
bool fixed = false;
if (i == 1 && s[i] == '1') L = a[i], fixed = true;
while ((s[i] != '0' || idx == i) && i <= n) {
M = min(M, c[i] - delta);
if (c[i] > c[i - 1] || i == 1) {
if (!fixed || L == c[i] - delta) {
L = c[i] - delta;
fixed = true;
} else {
ok = false;
break;
}
}
if (c[i] < c[i - 1] && i != 1) {
ok = false;
break;
}
i++;
delta += a[i];
}
if (fixed && L > M) {
ok = false;
}
if (!ok) break;
b[idx] = (fixed ? L : M);
} else {
i++;
}
}
if (!ok) {
cout << "No" << '\n';
} else {
cout << "Yes" << '\n';
ll sum = 0;
for (int i = 1; i <= n; i++) {
if (s[i] == '0') {
a[i] = b[i] - sum;
sum += a[i];
} else {
sum += a[i];
}
cout << a[i] << ' ';
}
cout << '\n';
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) solve();
return 0;
}