不太一样的写法,感觉比较容易理解一点。码量也比较短。
首先我们要发现:一个序列如果目前是升序的,那么它不管删多少个数(中间不再加数),最终还是升序的;如果目前不是升序,那么不管加多少个数,最终也不是升序。
这启发我们用两个数组 \(up_i\) 和 \(down_i\) 记录当前长度为 \(i\) 的序列是升序还是不是升序。如果存在一个时刻序列长度为 \(i\),并且 \(up_i\) 和 \(down_i\) 都是 \(1\),也就是既是升序也不是升序,那么就不合法。(情况1)
不合法的情况还有一种,就是当序列长度小于等于 \(1\) 时,操作序列说此时不是升序,那么根据题意,也是不合法的。(情况2)
\(up\) 和 \(down\) 的转移非常简单,如果长度 \(now\) 减 \(1\),并且 \(up_{now}=1\),那么 \(up_{now-1}=up_{now}\),同时把 \(up_{now}=down_{now}=0\),表示未知;如果长度 \(now\) 加 \(1\),那么只需要转移 \(down_{now+1}=down_{now}\)。
所以这题我们只需要发现上面的性质就好写了,虽然比别人多个数组来做有点蠢。
AC code:
#include <bits/stdc++.h>
typedef long long ll;
int read() {
int x = 0, f = 1;
char c = getchar();
while(!isdigit(c)) {
if(c == '-') f = -1;
c = getchar();
}
while(isdigit(c)) {
x = (x << 3) + (x << 1) + (c - '0');
c = getchar();
}
return x * f;
}
int t;
char a[200010];
int up[200010], down[200010];
void Solve() {
t = read();
while(t--) {
std::cin >> a + 1;
int n = strlen(a + 1), now = 0;
bool flg = 0;
memset(up, 0, sizeof(up));
memset(down, 0, sizeof(down)); //这样初始化没有 tle 有点神奇。
for(int i = 1; i <= n; i++) {
if(a[i] == '+' || a[i] == '-') {
if(a[i] == '+') {
down[now + 1] = down[now];
now++;
}
else {
down[now] = 0;
if(up[now]) up[now - 1] = up[now]; //注意判断,因为这个调了好久qwq
up[now] = 0;
now--;
}
}
else {
if(now <= 1 && a[i] == '0') flg = 1; //情况2
if(a[i] == '1') up[now] = 1;
else down[now] = 1; //根据操作序列更新数组
if(up[now] && down[now]) flg = 1; //情况1
}
}
if(flg) std::cout << "NO\n";
else std::cout << "YES\n";
}
}
int main() {
Solve();
return 0;
}
标签:int,up,down,CF1861C,序列,Queries,升序,Array,now
From: https://www.cnblogs.com/FireRaku/p/18092166