1 solutions
-
2
神奇消消乐。。emm,确实挺神奇的。
题意
题意很简单:给定循环次数 ,每次向数列末尾添加一个数 。如果数列的某个子段满足消除的条件,就会删除这个子段。对于每次操作,询问数列的长度。
消除条件:连续的 个数,每个数都是 。
思路
首先要明确一点:每次操作时,仅会在数列末尾产生至多一次删除操作。
推导:假定当前数列中没有可删除的子段,即,最多只有连续 个 。而每次添加的数有可能刚好凑齐了连续 个 ,并发生了删除操作。
我们发现,所有删除操作都在数列末尾,这与栈 的弹出操作很像啊!考虑用栈维护。
考虑维护两个栈。一个栈
stk
存放数列中的数 ,以便和新添加的数做比较。另一个栈cnt
存放数列中 对应位置上 的连续长度 ,。(也就是说当前有 个连续的 )如果发现 ,在两个栈中同时弹出 个元素,以此模拟消除操作。
实现
维护两个栈,两个栈还要同步操作,而且还要 弹出多个元素。用STL显然力不从心了,考虑手动维护两个栈,这样每次进出栈的复杂度就都是 了。每次操作输出栈的大小即可。
#include <iostream> using namespace std; const int N = 2e5+10; int n, stk[N], cnt[N], tot; // tot:栈的大小,默认为0 int main() { cin>>n; stk[0] = -1; // 记得考虑设置初始值(本题没有必要) for(int i=1;i<=n;++i) { // 加入新元素 cin>>stk[++tot]; cnt[tot] = 1; if(stk[tot]==stk[tot-1]) // 如果相等,更新长度cnt cnt[tot] += cnt[tot-1]; // 如果满足删除条件,按要求删除栈顶的stk[tot]个元素 if(cnt[tot]==stk[tot]) tot-=stk[tot]; cout<<tot<<"\n"; // 输出栈的大小 } return 0; }
- 1
Information
- ID
- 937
- Time
- 1000ms
- Memory
- 256MiB
- Difficulty
- 9
- Tags
- (None)
- # Submissions
- 60
- Accepted
- 6
- Uploaded By