foj 2260 Card Game 模拟 或区间最值 福州大学第十四届程序设计竞赛H题
来源:互联网 发布:开机很久网络连接 编辑:程序博客网 时间:2024/06/05 14:15
题目链接:
http://acm.fzu.edu.cn/problem.php?pid=2260
题意:
直接看题目,说的很清楚,或者我复制一遍题面好了
有如下取牌游戏:
桌面上有n张卡牌从左到右排成一行,每张卡牌上有一个数字;
游戏按轮次进行,每一轮中取掉所有比左边数值小的卡牌;
当无牌可取的时候则游戏结束。
比如初始卡牌为{5, 6, 3, 7, 4, 1, 2},共需2轮取牌。取牌过程如下(小括号为每轮取掉的牌):
{5, 6, 3, 7, 4, 1, 2}
==> {5, 6, (3), 7, (4), (1), 2}
==> {5, 6, 7, 2}
==> {5, 6, 7, (2)}
==> {5, 6, 7}
现按顺序给定初始的卡牌数字,请求出游戏结束时取牌的总轮次,并输出结束时桌上剩余的卡牌序列。
模拟
现在感觉最正确的思路应该就是Claris老师(%%%)的模拟了,这应该比较好想把(队友质问我为什么比赛的时候没有想到,其实自己写了一发暴力模拟,t了之后就拿它来对拍自己的其他思路了……因为用的stl的链表,所以没想手写链表可以有很大的优化,真的太蠢了QAQ
模拟当然就是用链表裸的模拟了,把当前要删除的节点放在队列里,删的同时看被删的节点的后一个节点下一轮会不会被删,被删的话就放进下一轮要删除的队列里,每次循环的时候交换队列就好了
复杂度O(n)
代码:
#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#define PB push_backtypedef long long LL;typedef pair<int, int> P;const int MAXN = 1e6 + 5;const int INF = 0x3f3f3f3f;struct Node { int pre, nxt, val;};int n;int num[MAXN], tot;int q[2][MAXN], la, lb;int *qa, *qb;bool used[MAXN], changed;Node nodes[MAXN];void Erase(int x) { if (used[x]) return ; used[x] = true; changed = true; int nxt = nodes[x].nxt; nodes[nodes[x].pre].nxt = nodes[x].nxt; nodes[nodes[x].nxt].pre = nodes[x].pre; if (nodes[nodes[nxt].pre].val > nodes[nxt].val) qb[lb++] = nxt;}int main() { while (~scanf("%d", &n)) { for (int i = 0; i < n; ++i) { scanf("%d", &nodes[i].val); used[i] = false; nodes[i].pre = i - 1; nodes[i].nxt = i + 1; } nodes[0].pre = 0; nodes[n - 1].nxt = n - 1; int mx = nodes[0].val; tot = 0; used[0] = true; qa = q[0]; qb = q[1]; la = lb = 0; for (int i = 1; i < n; ++i) { if (mx <= nodes[i].val) { num[tot++] = mx; mx = nodes[i].val; used[i] = true; } if (nodes[i - 1].val > nodes[i].val) { qa[la++] = i; } } num[tot++] = mx; changed = true; int ans = -1; while (changed) { ++ans; changed = false; lb = 0; for (int i = 0; i < la; ++i) Erase(qa[i]); swap(qa, qb); swap(la, lb); } printf("%d\n%d", ans, num[0]); for (int i = 1; i < tot; ++i) printf(" %d", num[i]); putchar(10); }}
区间最值
不难看出,如果一个数要消失,那它一定是撞到前一个比它大的数才消失,如果它与前一个比它大的数之间有其它数,那么这些数消失之前,它都不会消失。
用数组f[]
标记每个元素什么时候消失,如果一个元素的前一个元素就是那个比它大的数,那它毫无疑问第一次操作的时候就会消失。如果一个元素和比它大的那个元素之间相隔了一些元素,那么它消失的时间就是这些元素消失时间最大值加
= =,很扯的是,自己测了很多次,每次直接往前走到那个比它大的元素顺便记录区间最值的方法是最快的,复杂度update()
方法就能过,update()
则得卡一卡。
如果有人可以告诉我为什么
代码:
#include <cmath>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <queue>#include <vector>using namespace std;#define PB push_back#define lowbit(x) (x & (-x))#define MS(x, y) memset(x, y, sizeof(x))template<class T1, class T2> inline void gmax(T1& a, T2 b) { if (a < b) a = b; }typedef long long LL;typedef pair<int, int> P;const int MAXN = 1e6 + 5;const LL INF = 100000000000000000LL;int n;int a[MAXN], f[MAXN], pre[MAXN];P stk[MAXN];int tail;int num[MAXN], tot;int segTree[2100000], BASE;// 采用了zkw线段树void update(int x) { x += BASE; segTree[x] = f[x - BASE]; for (x >>= 1; x; x >>= 1) segTree[x] = max(segTree[x << 1], segTree[x << 1 | 1]);}int query(int l, int r) { int ret = 0; l += BASE - 1; r += BASE + 1; for (; l ^ r ^ 1; l >>= 1, r >>= 1) { if (~ l & 1) gmax(ret, segTree[l ^ 1]); if (r & 1) gmax(ret, segTree[r ^ 1]); } return ret;}int main() { while (~scanf("%d", &n)) { for (BASE = 1; BASE <= n + 1; BASE <<= 1); for (int i = 0; i <= BASE << 1; ++i) segTree[i] = 0; int ans = 0, mx = 0, tot = 0, x; tail = 0; for (int i = 1; i <= n; ++i) scanf("%d", a + i); // 用单调栈记录每个数前面比它大的数的位置 stk[tail++] = P(a[1], 1); for (int i = 2; i <= n; ++i) { while (tail > 0 && stk[tail - 1].first <= a[i]) --tail; pre[i] = stk[tail - 1].second; stk[tail++] = P(a[i], i); } for (int i = 1; i <= n; ++i) { if (a[i] >= mx) { num[tot++] = mx; mx = a[i]; f[i] = 0; } else { if (a[i - 1] > a[i]) { f[i] = 1; } else { f[i] = query(pre[i] + 1, i - 1) + 1; } } gmax(ans, f[i]); update(i); } num[tot++] = mx; printf("%d\n%d", ans, num[1]); for (int i = 2; i < tot; ++i) printf(" %d", num[i]); putchar(10); }}
- foj 2260 Card Game 模拟 或区间最值 福州大学第十四届程序设计竞赛H题
- 福州大学第十四届程序设计竞赛--平行四边形数
- FZU 2253 Salty Fish (最大区间和)(福州大学第十四届程序设计竞赛)
- FZU2253 Salty Fish(最大区间和)(福州大学第十四届程序设计竞赛)
- FZU2261 浪里个浪(最短路,spfa)(福州大学第十四届程序设计竞赛)
- 福州大学第十四届程序设计竞赛-重现赛(Record)
- 福州大学第十四届程序设计竞赛_重现赛 I
- 福州大学第十四届程序设计竞赛_重现赛 J
- 福州大学第十四届程序设计竞赛训练总结【7/9】
- 福州大学第十四届程序设计竞赛_重现赛
- (补题心路)福州大学第十四届程序设计竞赛_重现赛
- 福州大学第十二届程序设计竞赛-H - 最小花费
- foj Problem 2232 炉石传说 福州大学第十三届程序设计竞赛_重现 二分图
- 福州大学第十一届程序设计竞赛
- 福州大学第十一届程序设计竞赛
- 福州大学第十一届程序设计竞赛
- 福州大学第十二届程序设计竞赛
- 福州大学第十四届程序设计竞赛_重现赛 A Salty Fish(思路)
- postgresql、cmin、cmax,单条sql插入多上数据.md
- 嵌套的数组进行扁平化处理
- Python:堆排序算法
- [译]TF-api(2) tf.nn.lrn
- java学习1 mac 下Tomcat的环境搭建
- foj 2260 Card Game 模拟 或区间最值 福州大学第十四届程序设计竞赛H题
- Hibernate连接oracle数据库:外部(远程)数据库和内部(本地)数据库
- 2017-07-19:NOIP2016Day1
- Unity中物体运动方法总结
- Yarn的原理与资源调度
- Android添加一个回调监听接口
- spring属性的注入为什么不支持接口注入
- Could not resolve placeholder 'driver' in string value "${driver}"
- getopt在Python中的使用(转)