链接
题意
CCPC东北四省的1008。
需要实现一个双端栈结构,可以从两端push和pop,存的元素只有1/0两种,并且需要支持查询左端到右端或右端到左端元素依次nand的值。
题解
感觉就是个脑洞题,一开始想复杂了,可以发现nand这种操作并不满足交换律和结合律,所以线段树啥的基本维护不了。
需要看出来nand到0的时候一定是1,并且如果一段数全是1,那么nand的值和奇偶性是相关的。这样记录当前栈0的位置就好了,使用双端队列就可以,进栈出栈的时候加个判断(有个特殊情况,0的某侧是否有元素,如果没元素那么不+1)。
代码
#include <cstdio>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
#define maxn (400040)
struct _stack{
#define X0 (maxn >> 1)
deque<int> D;
int a[maxn], left, right, dir, sz;
void init() { dir = 1, sz = 0, left = right = X0; D.clear(); }
void REVERSE() {
dir = dir ? 0 : 1;
}
void PUSH(int x)
{
if(dir) {
if(x == 0) D.push_back(right);
a[right++] = x;
} else {
a[--left] = x;
if(x == 0) D.push_front(left);
}
sz++;
}
void POP()
{
if(dir) {
right--;
if(a[right] == 0) D.pop_back();
} else {
if(a[left] == 0) D.pop_front();
left++;
}
sz--;
}
int QUERY()
{
if(sz == 0) printf("Invalid.\n");
else if(D.empty()) {
printf("%d\n", (right - left) % 2);
} else if(!dir) {
printf("%d\n", (right - 1 - D.back() + (left < D.back())) % 2);
} else {
printf("%d\n", (D.front() - left + (right > D.front() + 1)) % 2);
}
}
} fstack;
int main()
{
int T, kase = 0;
cin >> T;
while(T--)
{
fstack.init();
int N;
cin >> N;
char op[10]; int x;
printf("Case #%d:\n", ++kase);
while(N--)
{
scanf("%s", op);
switch(op[0])
{
case 'P':
if(op[1] == 'U')
{
scanf("%d", &x);
fstack.PUSH(x);
}
else
fstack.POP();
break;
case 'R':
fstack.REVERSE();
break;
case 'Q':
fstack.QUERY();
break;
}
}
}
return 0;
}