我解决的:E、I、F。
没看的:C、H。
旁观的:G、M、B、D、L、K。
看了但没做出来的:A、J。
E Eggfruit Cake
简单题,略。
I Improve SPAM
简单拓扑排序,略。
M Mountain Ranges
简单题,略。
K Know your Aliens
简单构造题,略。
F Fabricating Sculptures
题意:给定 ,求出所有“单峰拆分”的方案数。单峰拆分即将 拆分成 个正整数 ,且 ,使得 到 不降, 到 不增。 。
设 为将 拆分成 个数的“单峰拆分”的方案数。
对于 ,显然 。
对于 ,那么 。
对于
,考虑将每一个数都减去 1,然后看看剩余的非 0 数有多少。于是
其中
就表示剩余的非 0 数个数,这些数可以来自
的长为
的子区间的任意一个,所以要乘一个
。
用两个前缀和优化转移即可做到时间复杂度为 。
G Gluing Pictures
题意:给定串 ,多次询问串 ,问 最少要用几个 的子串构成。
辅以 SAM 贪心即可。
A Algorithm Teaching
DAG 上最长反链,略。我不知道这个模型,没做出来…
L Leverage MDT
题意:给一个 01 矩阵,可以选择一些行翻转。问可能达到的最大全 1 子矩阵大小。
由于可以翻转,因此只要一段值都相等就有可能构成子矩阵。也就是说,0000
和 1111
作为答案的一部分时,是没有区别的。
因此可以枚举作为最右端的列,算一下最靠右段的长度,然后就转化为了一个经典的单调栈问题。
#include <bits/stdc++.h>
using namespace std;
int n, m;
char s[1005][1005];
int h[1005], st[1005][2], top;
int main(){
scanf("%d%d", &n, &m);
for (int i = 0; i < n; ++i){
scanf("%s", s[i]);
h[i] = 1;
}
h[n] = 0;
int ans = 1;
for (int i = 1; i < m; ++i){
for (int j = 0; j < n; ++j){
if (s[j][i] == s[j][i - 1])
++h[j];
else h[j] = 1;
}
top = 0;
for (int j = 0; j <= n; ++j){
int curw = 0;
while (top > 0 && h[j] <= st[top][0]){
curw += st[top][1];
ans = max(ans, min(curw, st[top][0]));
--top;
}
st[++top][0] = h[j], st[top][1] = curw + 1;
}
}
printf("%d\n", ans * ans);
return 0;
}
C Cut Inequality Down
题意:有 天,第 天可以获得 元。第 天结束时,手头上的钱要和 取 ,和 取 。多组询问,问若第 天开始时有 元,那么第 天结束时有多少钱。
称钱超过 为上溢,少于 为下溢。容易发现,第 天结束时如果溢出了,那么后面的钱的变化是确定的。当然,如果始终不溢出,那么最终的钱也是确定的。
于是我们可以用 ST 表和二分算出:某天开始时,如果有 元,那么之后最早哪一天会溢出。然后倍增处理一下:第 天开始时如果钱是 或者 ,那么之后最早哪一天会溢出,是上溢还是下溢。
预处理完后跑倍增回答询问即可。时间复杂度 。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int read(){
int f = 1, x = 0;
char c = getchar();
while (c < '0' || c > '9'){if(c == '-') f = -f; c = getchar();}
while (c >= '0' && c <= '9')x = x * 10 + c - '0', c = getchar();
return f * x;
}
int n, L, U, a[100005], logg[100005];
ll sum[100005], f[100005][18], g[100005][18];
int nxt[100005][18][2][2] = {0};
inline ll getmax(int l, int r){
int p = logg[r - l + 1];
return max(f[l][p], f[r - (1 << p) + 1][p]);
}
inline ll getmin(int l, int r){
int p = logg[r - l + 1];
return min(g[l][p], g[r - (1 << p) + 1][p]);
}
int gethi(int st, int x){
int l = st, r = n + 1;
while (r > l){
int mid = (l + r) >> 1;
if (x - sum[st - 1] + getmax(st, mid) >= U)
r = mid;
else l = mid + 1;
}
return l > n ? 0: l;
}
int getlo(int st, int x){
int l = st, r = n + 1;
while (r > l){
int mid = (l + r) >> 1;
if (x - sum[st - 1] + getmin(st, mid) <= L)
r = mid;
else l = mid + 1;
}
return l > n ? 0: l;
}
void init(){
n = read(), L = read(), U = read();
sum[0] = 0;
for (int i = 1; i <= n; ++i){
a[i] = read(), sum[i] = sum[i - 1] + a[i],
f[i][0] = g[i][0] = sum[i];
}
logg[0] = -1;
for (int i = 1; i <= n; ++i)
logg[i] = logg[i >> 1] + 1;
for (int j = 1; j <= logg[n]; ++j){
int p = (1 << j);
for (int i = 1; i + p - 1 <= n; ++i){
f[i][j] = max(f[i][j - 1], f[i + (p >> 1)][j - 1]);
g[i][j] = min(g[i][j - 1], g[i + (p >> 1)][j - 1]);
}
}
for (int i = n, rb1, rb2; i >= 1; --i){
rb1 = gethi(i, U), rb2 = getlo(i, U);
if (!rb2 || (rb1 > 0 && rb1 < rb2))
nxt[i][0][0][0] = rb1, nxt[i][0][0][1] = 0;
else
nxt[i][0][0][0] = rb2, nxt[i][0][0][1] = 1;
rb1 = gethi(i, L), rb2 = getlo(i, L);
if (!rb2 || (rb1 > 0 && rb1 < rb2))
nxt[i][0][1][0] = rb1, nxt[i][0][1][1] = 0;
else
nxt[i][0][1][0] = rb2, nxt[i][0][1][1] = 1;
for (int j = 1, to, tp; ; ++j){
bool flag = false;
to = nxt[i][j - 1][0][0] + 1, tp = nxt[i][j - 1][0][1];
if (to > 1){
nxt[i][j][0][0] = nxt[to][j - 1][tp][0];
nxt[i][j][0][1] = nxt[to][j - 1][tp][1];
flag = true;
}
to = nxt[i][j - 1][1][0] + 1, tp = nxt[i][j - 1][1][1];
if (to > 1){
nxt[i][j][1][0] = nxt[to][j - 1][tp][0];
nxt[i][j][1][1] = nxt[to][j - 1][tp][1];
flag = true;
}
if (!flag) {
break;
}
}
}
}
void query(int st, int ed, int x){
int rb1 = gethi(st, x), rb2 = getlo(st, x);
if (rb1 == 0) rb1 = n + 1;
if (rb2 == 0) rb2 = n + 1;
int o;
if (rb1 < rb2){
if (rb1 > ed) {
printf("%lld\n", x + sum[ed] - sum[st - 1]);
return ;
} else if (rb1 == ed) {
printf("%d\n", U);
return ;
} else {
st = rb1 + 1, x = U, o = 0;
}
} else {
if (rb2 > ed) {
printf("%lld\n", x + sum[ed] - sum[st - 1]);
return ;
} else if (rb2 == ed) {
printf("%d\n", L);
return ;
} else {
st = rb2 + 1, x = L, o = 1;
}
}
for (int j = logg[n]; j >= 0; --j){
int to = nxt[st][j][o][0], tp = nxt[st][j][o][1];
if (!to) continue;
if (to == ed) {
printf("%d\n", (tp == 0 ? U: L));
return ;
} else if (to < ed){
st = to + 1, x = (tp == 0 ? U: L), o = tp;
}
}
printf("%lld\n", x + sum[ed] - sum[st - 1]);
}
void solve(){
int q = read();
while (q--){
int st = read(), ed = read(), x = read();
query(st, ed, x);
}
}
int main(){
init();
solve();
return 0;
}
D Dazzling stars
待补。。。
J Jumping Grasshoper
待补。。。
H Hold or Continue?
待补。。。