当前位置: 首页 > news >正文

【倍增】P10264 [GESP202403 八级] 接竹竿|普及+

[GESP202403 八级] 接竹竿

题目描述

小杨同学想用卡牌玩一种叫做“接竹竿”的游戏。

游戏规则是:每张牌上有一个点数 v v v,将给定的牌依次放入一列牌的末端。若放入之前这列牌中已有与这张牌点数相
同的牌,则小杨同学会将这张牌和点数相同的牌之间的所有牌全部取出队列(包括这两张牌本身)。

小杨同学现在有一个长度为 n n n 的卡牌序列 A A A,其中每张牌的点数为 A i A_i Ai 1 ≤ i ≤ n 1\le i\le n 1in)。小杨同学有 q q q 次询问。第 i i i 次( 1 ≤ i ≤ q 1\le i\le q 1iq)询问时,小杨同学会给出 l i , r i l_i,r_i li,ri 小杨同学想知道如果用下标在 [ l i , r i ] [l_i,r_i] [li,ri] 的所有卡牌按照下标顺序玩“接竹竿”的游戏,最后队列中剩余的牌数。

输入格式

一行包含一个正整数 T T T,表示测试数据组数。

对于每组测试数据,第一行包含一个正整数 n n n,表示卡牌序列 A A A 的长度。

第二行包含 n n n 个正整数 A 1 , A 2 , … , A n A_1,A_2,\dots,A_n A1,A2,,An,表示卡牌的点数 A A A

第三行包含一个正整数 q q q,表示询问次数。

接下来 q q q 行,每行两个正整数 l i , r i l_i,r_i li,ri 表示一组询问。

输出格式

对于每组数据,输出 q q q 行。第 i i i 行( 1 ≤ i ≤ q 1\le i\le q 1iq)输出一个非负整数,表示第 i i i 次询问的答案。

样例 #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 , 2 1,2,2 1,2,2 的顺序放置卡牌,在放置最后一张卡牌时,两张点数为 2 2 2 的卡牌会被收走,因此最后队列中只剩余一张点数为 1 1 1 的卡牌。

对于第二次询问,队列变化情况为:

{ } → { 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}。因此最后队列中只剩余一张点数为 3 3 3 的卡牌。

数据范围

子任务分数 T T T n n n q q q max ⁡ A i \max A_i maxAi特殊条件
1 1 1 30 30 30 ≤ 5 \le 5 5 ≤ 100 \le100 100 ≤ 100 \le100 100 ≤ 13 \le13 13
2 2 2 30 30 30 ≤ 5 \le 5 5 ≤ 1.5 × 1 0 4 \le 1.5\times10^4 1.5×104 ≤ 1.5 × 1 0 4 \le 1.5\times10^4 1.5×104 ≤ 13 \le13 13所有询问的右端点等于 n n n
3 3 3 40 40 40 ≤ 5 \le 5 5 ≤ 1.5 × 1 0 4 \le 1.5\times10^4 1.5×104 ≤ 1.5 × 1 0 4 \le 1.5\times10^4 1.5×104 ≤ 13 \le13 13

对于全部数据,保证有 1 ≤ T ≤ 5 1\le T\le 5 1T5 1 ≤ n ≤ 1.5 × 1 0 4 1\le n\le 1.5\times 10^4 1n1.5×104 1 ≤ q ≤ 1.5 × 1 0 4 1\le q\le 1.5\times 10^4 1q1.5×104 1 ≤ A i ≤ 13 1\le A_i\le 13 1Ai13

倍增

b[i] ,b[i] > i,a[i] == a[b[i]],且i最小。b[i]是消掉i的牌。
c[i][j] 记录a[i,i+2j-1]剩下的第一张牌,如果可以消掉所有牌,为-1。-2表示未计算。
f(i,len)求左闭右开空间a[i,i+len),第一张未消除的牌。其逻辑如下:
2j < len,且j最大。将区间分成左右两个区间,左区间长2j,余下的是右半区间。
情况一,x1 = c[i][j],如果x1=-1,返回f(右区间)
情况二,x2=b[x1] >= i+len,返回x1
情况三,x2 <i+len,返回f(x+1,len-(x+1-i))
情况二,直接返回结果,时间复杂度O(1);情况一和情况三长度至少减少一半,时间复杂度O(logn)。
两种特殊情况要处理:
len = min(len, N - i);
如果len <=0,返回-1。
如果len刚好是2的整数次幂,且c[i][j+1] 不为-2,则直接返回。
函数g(i,len)求左闭右开空间a[i,i+len)剩余的牌数。由于本题解是0开始,故每次查询的答案是g(Left-1,r-left+1)。
x = f(i,len) 如果x 是-1,返回0。
否则返回1+g(x+1,len-(x+1-i))
特殊处理:
len = min(len, N - i);
len <=0返回0。
由于只有13张牌,故只顶多调用g函数13次。每次查询的时间复杂度是O(logn13)
c[i]0]=i
j从1到15,i从0到n-1 计算c。

代码

核心代码

#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>

#include <bitset>
using namespace std;

template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {
	in >> pr.first >> pr.second;
	return in;
}

template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {
	in >> get<0>(t) >> get<1>(t) >> get<2>(t) ;
	return in;
}

template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {
	in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);
	return in;
}

template<class T = int>
vector<T> Read() {
	int n;
	scanf("%d", &n);
	vector<T> ret(n);
	for(int i=0;i < n ;i++) {
		cin >> ret[i];
	}
	return ret;
}

template<class T = int>
vector<T> Read(int n) {
	vector<T> ret(n);
	for (int i = 0; i < n; i++) {
		cin >> ret[i];
	}
	return ret;
}

class Solution {
public:
	vector<int> Ans(vector<int>& a, vector<pair<int, int>>& que) {
		const int N = a.size();
		vector<int> b(N, N), next(14, N);
		for (int i = N - 1; i >= 0; i--) {
			b[i] = next[a[i]];
			next[a[i]] = i;
		}
		const int M = 15;
		vector<vector<int>> c(N, vector<int>(M + 1, -2));
		function<int(int, int)> F = [&](int i, int len) {
			len = min(len, N - i);
			if (len <= 0) { return -1; };
			int j = 0;
			while ((1 << j) < len) { j++; }
			if (((1 << j) == len) && (-2 != c[i][j])) { return c[i][j]; }
			j--;
			auto x = c[i][j];
			const auto& len1 = 1 << j;
			if (-1 == x) { return F(i + len1, len - len1); }
			if (b[x] >= i + len)return x;
			return F(b[x] + 1, len - (b[x] + 1 - i));
		};
		for (int i = 0; i < N; i++) { c[i][0] = i; }
		for (int j = 1; j <= M; j++) {
			for (int i = 0; i < N; i++) { c[i][j] = F(i, 1 << j); }
		}
		function<int(int, int)> G = [&](int i, int len) {
			len = min(len, N - i);
			if (len <= 0) { return 0; }
			int x = F(i, len);
			if (-1 == x) { return 0; }
			return 1 + G(x + 1, len - (x + 1 - i));
		};
		vector<int> ans;
		for (const auto& [left, r] : que) {
			ans.emplace_back(G(left - 1, r - left + 1));
		}
		return ans;
	}
};


int main() {
#ifdef _DEBUG
	freopen("a.in", "r", stdin);
#endif // DEBUG	
	int T = 0;
	cin >> T;
	while(T--){
		auto a = Read<int>();
		auto que = Read<pair<int, int>>();
#ifdef _DEBUG		
		//printf("N=%d", n);
	/*	Out(a, "a=");
		Out(que, ",que=");*/
#endif // DEBUG	
		auto res = Solution().Ans(a,que);
		for (const auto& i : res)
		{
			cout << i << endl;
		}
	}
	return 0;
}

单元测试

vector<int> a;
		vector<pair<int, int>> que;
		TEST_METHOD(TestMethod11)
		{
			a = { 1,2,2,3,1,3 }, que = { {1,3},{1,6},{1,5},{5,6} };
			auto res = Solution().Ans(a,que);
			AssertEx({ 1,1,0,2 }, res);
		}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。


文章转载自:
http://beneficiation.alwpc.cn
http://asymmetry.alwpc.cn
http://bathing.alwpc.cn
http://auxotrophy.alwpc.cn
http://acetimeter.alwpc.cn
http://chapstick.alwpc.cn
http://cacique.alwpc.cn
http://bortsch.alwpc.cn
http://armomancy.alwpc.cn
http://bemoisten.alwpc.cn
http://cerebrotomy.alwpc.cn
http://alula.alwpc.cn
http://bizarre.alwpc.cn
http://chairborne.alwpc.cn
http://bazookier.alwpc.cn
http://cheering.alwpc.cn
http://anemochory.alwpc.cn
http://celt.alwpc.cn
http://awhirl.alwpc.cn
http://chimera.alwpc.cn
http://brolga.alwpc.cn
http://bathypelagic.alwpc.cn
http://bedeman.alwpc.cn
http://alfur.alwpc.cn
http://brachiocephalic.alwpc.cn
http://apophyllite.alwpc.cn
http://chechia.alwpc.cn
http://bisync.alwpc.cn
http://babiroussa.alwpc.cn
http://adonai.alwpc.cn
http://www.dtcms.com/a/123364.html

相关文章:

  • java继承练习
  • 走多远(拓扑排序,dp)
  • ChatRoom测试报告
  • 手眼标定-眼在手上
  • 安卓设备配置PAC代理服务器的完整指南:实现智能分流与开发加速
  • OfficePlus去掉PDF文件右键菜单里的PDF转换
  • Java Map和Set集合应用
  • docker安装nginx,基础命令,目录结构,配置文件结构
  • 0410 | 软考高项笔记:项目管理概述
  • jQuery多库共存
  • 甘特图和里程碑趋势图在项目监控中有哪些实际应用?
  • 本地laravel项目【dcat-admin】部署到liunx服务器
  • 论文笔记:Dynamic Spectral Graph Anomaly Detection
  • 先占个日常,等会写。
  • 如何白嫖Grok3 API? 如何使用Grok3 API调用实例?怎么使用Grok3模型?
  • 从零实现Agent智能体配置使用(Ragflow)
  • 多模态大模型在目标检测领域的最新进展
  • JS包装类型Object
  • AutoKeras 处理图像回归预测
  • spark-core学习内容总结
  • 【完美解决】VSCode连接HPC节点,已配置密钥却还是提示需要输入密码
  • 京华幻梦:科技自然共生诗篇
  • 【蓝桥杯】二分查找
  • springcloud进阶
  • SkyWalking + ELK 全链路监控系统整合指南
  • FPGA_DDR(二)
  • Go语言编写一个进销存Web软件的demo
  • python基础语法1:输入输出
  • Java 基础 - 反射(1)
  • Java学习——day26(线程同步与共享资源保护)