1 条题解
-
1
【题目大意】接竹竿游戏规则为按顺序依次加入一个牌堆,如果发现牌堆中有一对相同的牌,则将两张牌中间的牌(包含两张牌)全部拿出,求最终牌堆有多少牌。
有一个序列 ,有 次询问,每次询问给出 ,求出 的接竹竿结果。
【考纲知识点】倍增,RMQ
【解题思路】根据题意,每张牌最大的数字是13,然后根据提供的区间,看长度最远的2个数字,去掉后剩下的卡牌数量。注意:按照队列方式入队,遇到相同的数字,之间的卡牌数字就全部消失。例如,1,2,3,1,4,2,3。消失的是1231,而不是23142这个区间。另一种情况,如果是3个1,例如1,2,1,3,1,4,2,会消除121这3张卡牌。
结论:记录下一个出现的数字;求该区间内,第一个和它相同的数字。用区间最值来求。
从左到右去查找,如果第1个数字,队列后面没有相同的,继续判断第2个。
求解:区间是[L,R],和第1个数字相同的最近数字的位置,该位置不能超过R。依次类推求第2个,第3个……。
可以用区间最值RMQ来统计。注意要倒序处理,从n到1;
【参考程序】
#include <bits/stdc++.h> using namespace std; #define ll long long const int N = 1e5 + 10; int a[N]; int nxt[N][30], pos[20]; int main() { int t; cin >> t; while (t--) { int n; cin >> n; memset(pos, 0, sizeof pos); for (int i = 1; i <= n; i++) { cin >> a[i]; for (int j = 0; j <= 20; j++) nxt[i][j] = n + 1; } for (int i = n; i >= 1; i--) { if (!pos[a[i]]) { nxt[a[i]][0] = n + 1; pos[a[i]] = i; } else { nxt[i][0] = pos[a[i]]; pos[a[i]] = i; } } for (int i = n; i >= 1; i--) { for (int j = 1; j <= 20; j++) { if (nxt[i][j - 1] + 1 <= n) nxt[i][j] = nxt[nxt[i][j - 1] + 1][j - 1]; } } int q; cin >> q; while (q--) { int l, r; cin >> l >> r; int ii = l; int ans = 0; while (ii <= r) { while (ii <= r && nxt[ii][0] > r) { ii++; ans++; } if (ii > r) break; for (int j = 20; j >= 0; j--) { if (nxt[ii][j] <= r) { ii = nxt[ii][j]; break; } } ii++; } cout << ans << "\n"; } } }
- 1
信息
- ID
- 598
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 9
- 标签
- 递交数
- 13
- 已通过
- 3
- 上传者