题目描述
小杨同学想用卡牌玩一种叫做“接竹竿”的游戏。
游戏规则是:每张牌上有一个点数 vvv,将给定的牌依次放入一列牌的末端。若放入之前这列牌中已有与这张牌点数相
同的牌,则小杨同学会将这张牌和点数相同的牌之间的所有牌全部取出队列(包括这两张牌本身)。
小杨同学现在有一个长度为 nnn 的卡牌序列 AAA,其中每张牌的点数为 AiA_iAi(1≤i≤n1\le i\le n1≤i≤n)。小杨同学有 qqq 次询问。第 iii 次(1≤i≤q1\le i\le q1≤i≤q)询问时,小杨同学会给出 li,ril_i,r_ili,ri 小杨同学想知道如果用下标在 [li,ri][l_i,r_i][li,ri] 的所有卡牌按照下标顺序玩“接竹竿”的游戏,最后队列中剩余的牌数。
输入格式
一行包含一个正整数 TTT,表示测试数据组数。
对于每组测试数据,第一行包含一个正整数 nnn,表示卡牌序列 AAA 的长度。
第二行包含 nnn 个正整数 A1,A2,…,AnA_1,A_2,\dots,A_nA1,A2,…,An,表示卡牌的点数 AAA。
第三行包含一个正整数 qqq,表示询问次数。
接下来 qqq 行,每行两个正整数 li,ril_i,r_ili,ri 表示一组询问。
输出格式
对于每组数据,输出 qqq 行。第 iii 行(1≤i≤q1\le i\le q1≤i≤q)输出一个非负整数,表示第 iii 次询问的答案。
输入输出样例 #1
输入 #1
1
6
1 2 2 3 1 3
4
1 3
1 6
1 5
5 6
输出 #1
1
1
0
2
说明/提示
样例解释
对于第一次询问,小杨同学会按照 1,2,21,2,21,2,2 的顺序放置卡牌,在放置最后一张卡牌时,两张点数为 222 的卡牌会被收走,因此最后队列中只剩余一张点数为 111 的卡牌。
对于第二次询问,队列变化情况为:
{}→{1}→{1,2}→{1,2,2}→{1}→{1,3}→{1,3,1}→{}→{3}\{\}\to\{1\}\to\{1,2\}\to\{1,2,2\}\to\{1\}\to\{1,3\}\to\{1,3,1\}\to\{\}\to\{3\}{}→{1}→{1,2}→{1,2,2}→{1}→{1,3}→{1,3,1}→{}→{3}。因此最后队列中只剩余一张点数为 333 的卡牌。
数据范围
子任务 | 分数 | TTT | nnn | qqq | maxAi\max A_imaxAi | 特殊条件 |
---|---|---|---|---|---|---|
111 | 303030 | ≤5\le 5≤5 | ≤100\le100≤100 | ≤100\le100≤100 | ≤13\le13≤13 | |
222 | 303030 | ≤5\le 5≤5 | ≤1.5×104\le 1.5\times10^4≤1.5×104 | ≤1.5×104\le 1.5\times10^4≤1.5×104 | ≤13\le13≤13 | 所有询问的右端点等于 nnn |
333 | 404040 | ≤5\le 5≤5 | ≤1.5×104\le 1.5\times10^4≤1.5×104 | ≤1.5×104\le 1.5\times10^4≤1.5×104 | ≤13\le13≤13 |
对于全部数据,保证有 1≤T≤51\le T\le 51≤T≤5,1≤n≤1.5×1041\le n\le 1.5\times 10^41≤n≤1.5×104,1≤q≤1.5×1041\le q\le 1.5\times 10^41≤q≤1.5×104,1≤Ai≤131\le A_i\le 131≤Ai≤13。
solution
可以记录一个每个纸牌的下一个相同纸牌的位置,这表示可以删除的一段,所以如果可以将从每一个纸牌开始可以删除的位置都记录下来,这样就好办了。但是有可能数据量太大,可以采用st表的方式,只记录 2i2^i2i 级别的。
代码
#include <iostream>
#include "bit"
#include "vector"
#include "unordered_set"
#include "unordered_map"
#include "set"
#include "queue"
#include "algorithm"
#include "bitset"
#include "cstring"
#include "cmath"using namespace std;const int N = 15001;int t, n, m, a[14], f[N][20]; // a[i] : 牌 i 上一次出现的位置
// vector<int> f[N]; // f[i][j] : 第 i 张牌的可以通过 2^j 次收牌达到的位置int main() {cin >> t;while (t--) {cin >> n;for (int i = 1; i <= n; i++)for (int j = 0; j < 20; j++)f[i][j] = n + 1;for (int i = 1; i <= n; i++) {int x;cin >> x;if (a[x]) f[a[x]][0] = i;a[x] = i;}for (int j = 1; j < 20; j++)for (int i = 1; i <= n; i++) {if (f[i][j - 1] < n)f[i][j] = f[f[i][j - 1] + 1][j - 1];}cin >> m;while (m--) {int l, r, s = 0, flag = 0;cin >> l >> r;while (l <= r) {int x = l;for (int j = 19; j >= 0; j--) {if (f[x][j] < r)x = f[x][j] + 1;else if (f[x][j] == r) {flag = 1;break;}}if (flag) break;if (x > l) l = x;else {s++, l++;}}cout << s << endl;}// 清空 amemset(a, 0, sizeof a);}
}