題目描述
小楊同學想用卡牌玩一種叫做“接竹竿”的游戲。
游戲規則是:每張牌上有一個點數 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 | max?Ai\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);}
}