10月28日G、H、I题
Train Problem I
题意:给出元素入栈顺序和出栈顺序,问该入栈顺序的条件下是否可能得到该出栈顺序。
分析:模拟。每次入栈后贪心匹配满足条件的出栈元素,最后判断栈是否为空。
const int N = 1e5+10;
char s1[N], s2[N];
int ans[N];
stack<char> st;
void run() {
int n;
while (~scanf("%lld%s%s",&n,s1+1,s2+1)) {
while (!st.empty()) st.pop();
int i = 0, j = 1, cnt = 0;
while (i++, i <= n) {
st.push(s1[i]), ans[++cnt] = 1;
while (!st.empty() && st.top() == s2[j]) st.pop(), j++, ans[++cnt] = 0;
}
if (!st.empty()) puts("No.");
else {
puts("Yes.");
rep(i,1,cnt) puts(ans[i] ? "in" : "out");
}
puts("FINISH");
}
}
Feel Good
题意:求max{子段和*该子段最小值}。
分析:单调栈。单调栈求最大矩形面积模板的宽改为子段和来更新答案即可。
const int N = 1e5+10;
int a[N], sum[N], st[N];
void run() {
int n = rd(), tail = 1, ans = 0, l = 1, r = 1;
rep(i,1,n) a[i] = rd(), sum[i] = sum[i-1] + a[i];
rep(i,1,n) {
bool flg = false;
int tmp;
while (tail > 1 && a[i] < a[st[tail-1]]) {
flg = true;
tmp = st[tail-1];
if ((sum[i-1] - sum[st[tail-1]-1]) * a[st[tail-1]] > ans) {
ans = (sum[i-1] - sum[st[tail-1]-1]) * a[st[tail-1]];
r = i-1, l = st[tail-1];
}
tail--;
}
if (flg) {
st[tail++] = tmp;
a[tmp] = a[i];
} else {
st[tail++] = i;
}
}
while (tail > 1) {
if ((sum[n] - sum[st[tail-1]-1]) * a[st[tail-1]] > ans) {
ans = (sum[n] - sum[st[tail-1]-1]) * a[st[tail-1]];
r = n, l = st[tail-1];
}
tail--;
}
pnt(ans);
put(l), pnt(r);
}
Vessels
题意:\(n\)个船从上向下叠,第\(i\)个船容积\(a[i]\)。
2个操作:
1.往下标\(p[i]\)的船注入\(x[i]\)的水,若已满则向下溢出。
2.查询下标为\(k[i]\)的船里有多少水。
分析:模拟。维护当前船往下还未注满水的第一艘船的下标。维护方法可以暴力优化或者并查集。
const int N = 2e5+10;
int c[N], a[N], fa[N];
int find(int x) {return x ^ fa[x] ? fa[x] = find(fa[x]) : x;}
void merge(int x, int y) {
x = find(x), y = find(y);
if (x != y) fa[x] = y;
}
void run() {
int n = rd();
rep(i,1,n) c[i] = rd();
rep(i,1,n+1) fa[i] = i;
int q = rd();
while (q--) {
if (rd() == 1) {
int p = rd(), x = rd();
while (x) {
p = find(p);
if (p > n) break;
if (a[p] + x >= c[p]) {
x -= c[p] - a[p];
a[p] = c[p];
merge(p, p+1);
} else {
a[p] += x;
break;
}
}
} else {
int k = rd();
pnt(a[k]);
}
}
}