蓝桥杯15届B组题解第二场

蓝桥杯14届B组题解(C++)

蓝桥杯14届B组题解C++(2)

传送阵

题目描述

小蓝在环球旅行时来到了一座古代遗迹,里面并排放置了 n 个传送阵,进入第 i 个传送阵会被传送到第 ai 个传送阵前,并且可以随时选择退出或者继续进入当前传送阵。小蓝为了探寻传送阵中的宝物,需要选择一个传送阵进入,然后连续进入之后的传送阵。小蓝希望尽可能多地进入传送门以便搜索宝物,同时他可以使用一次魔法,从某个传送阵 j 走到相邻的(第 j − 1 或第 j + 1 个)传送阵,请问小蓝最多能到达多少个不同的传送阵?一个传送阵可多次进入,但在计算答案时只算一个。

输入格式

输入的第一行包含一个正整数 n 。第二行包含 n 个正整数 a1, a2, · · · , an ,相邻整数之间使用一个空格分隔。

输出格式

输出一行包含一个整数表示答案。

样例输入
5
2 1 5 4 3
样例输出
4
提示

【样例说明】

小蓝的路径可以是:1 → 2 → 3 → 5 。其中 2 → 3 使用魔法。

【评测用例规模与约定】

对于 20% 的评测用例,1 ≤ n ≤ 1000 ;对于所有评测用例,1 ≤ n ≤ 106,且 a 是 1 至 n 的一个排列。

解题思维

可以利用并查集的思想,完成该题。

对于样例

2 1 5 4 3
在这里插入图片描述

它会有这样的三个不同并查集,且最大的大小当前为2。

遍历一遍数组,将两个相邻且属于不同并查集的合并大小,与当前最大的大小比较即可。

发现将1和5两个所在的并查集,合并后大小最大。

#include<bits/stdc++.h>
using namespace std;
#define int long long

const int N = 1e6+10;
int a[N];
int far[N];
int sz[N];
//寻找父节点
int findFa(int x)
{
	if(far[x]==x)
		return x;
	return findFa(far[x]);
}

signed main()
{
	
	int n;
	cin>>n;

	int m=0;
    //初始化,且获取数据
	for(int i=1;i<=n;i++) 
	{
		cin>>a[i];
		far[i]=i;
		sz[i]=1;
	}
    //实现并查集合。将其分为不同的集合。
	for(int i=1;i<=n;i++)
	{
		int cur =i;
		do{ 
			int cnt = a[cur];
			int f1 = findFa(cur);
			int f2 = findFa(cnt);
            //当自己的父节点就是自己时,标志着找不到新的节点合并了。
			if(f1 == f2)
				break;
            //将子节点的并查集合并到父节点的并查集。
			far[f1] = f2;
			sz[f2]+=sz[f1];
            //记录好当前最大的并查集的长度。
			m = max(m,sz[cnt]);
			cur = cnt;
			
		}while(cur!=far[cur]);
	}
	int f1 = findFa(1);
	int f2 = findFa(n);
	if(f1!=f2)
	{
		m = max(m,sz[1]+sz[n]);
	}

	for(int i=1;i<n;i++)
	{
        //依次尝试将两个不同并查集的大小合并。(也就是我们的魔法)
		f1 = findFa(i);
		f2 = findFa(i+1);
		if(f1!=f2)
		{
			m = max(m,sz[f1]+sz[f2]);
		}
	}
	cout<<m;
}

前缀总分

题目描述

给定 n 个由小写英文字母组成的字符串 s1, s2, · · · , sn ,定义前缀总分为V =∑i<j P(si, sj) ,其中 P(si, sj) 表示 si, sj 的最长公共前缀的长度。

小蓝可以选择其中一个字符串,并修改其中的一个字符。请问修改后前缀总分最大为多少?

输入格式

输入的第一行包含一个正整数 n 。接下来 n 行,每行包含一个字符串 si 。

输出格式

输出一行包含一个整数表示答案。

样例输入
3
aab
bbb
abb
样例输出
5
提示

【样例说明】

将第二个字符串改为 abb ,得分为 P(aab, abb)+P(aab, abb)+P(abb, abb) =1 + 1 + 3 = 5 。

【评测用例规模与约定】

对于 20% 的评测用例,1 ≤ n ≤ 20 ;

对于所有评测用例,1 ≤ n ≤ 200 ,1 ≤ |si| ≤ 200 ,其中 |si| 表示 si 的长度。

解题思路

可以先用例子找找关系

假设有两个字符串分别为,且已经找到了前缀总分sum
s1=a0a1a2a3s2=b0b1b2b3 s_1=a_0a_1a_2a_3\\ s_2=b_0b_1b_2b_3 s1=a0a1a2a3s2=b0b1b2b3
假设我们打算修改a1为其他的字符,
$$
记pre[i][j]表示,i,j字符串的最长公共子序列,而suf[k][i][j]表示以k位置开头的,i,j字符串的最长公共后缀长度。
\
\
只有当a1长度的字符之前和s2都已经匹配,以及a1变成了b1。那么

\此时的长度就会变为sum+suf[2][1][2]【2开头的,1和2字符串】+1
$$
其他情况见代码

#include<bits/stdc++.h> 
using namespace std;

const int N = 210;

//两个字符串最长公共前缀 i j
int pre[N][N];
//以K开头的两个公共字符串的最长后缀 K i j 
int suf[N][N][N];
//字符串
string s[N];
//获取两个字符串的最长公共前缀 
int getMaxPre(int i,int j)
{
	int m = min(s[i].size(),s[j].size());
	int k=0;
	for(int z=0;z<m;z++)
	{
		if(s[i][z]!=s[j][z])
			return k;
		k++;
	}
	return k;
}
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)cin>>s[i];
	int pans=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(i==j)continue;
			pre[i][j] = getMaxPre(i,j);
			if(i<j)
				pans+=pre[i][j];
			for(int k=min(s[i].size(),s[j].size())-1;k>=0;k--)
			{
				if(s[i][k]==s[j][k])
					suf[k][i][j]=suf[k+1][i][j]+1;
			}
		}
	}
	int ans=pans; 
	for(int i=1;i<=n;i++)
		for(int j=0;j<s[i].size();j++)
			for(char c='a';c<='z';c++)
				if(c!=s[i][j])
				{
					int t = pans;
					for(int k=1;k<=n;k++)
					{
						t-=pre[i][k];
						if(pre[i][k]<j)
							t+=pre[i][k];
						else if(c==s[k][j]&&pre[i][k]==j)
						{
							t+=j+suf[j+1][i][k]+1;
						}
						else
							t+=j;
					}
					ans = max(ans,t) ;
				}
	cout<<ans<<"\n";
	return 0;
}

遗迹

题目描述

小蓝找到了一个外星文明留下来的遗迹,遗迹大门的屏幕上有一个长度为m 的字符串 t 和一个输入框,下面还有一个键盘,键盘为一个长度为 n 的字符串 s ,由一个可以横向移动的指针来敲击键盘,指针可以向左移或向右移,不能移出键盘。

小蓝需要在键盘字符串 s 上先指定指针初始位置然后不断移动指针的位置,过程中通过敲击指针所在的字符来进行输入。然而,指针最多只能移动 L 的距离,小蓝想输入一个尽可能长的一个 t 的前缀,请问他最多能输入多少位。

输入格式

输入的第一行包含三个正整数 n, m, L ,相邻整数之间使用一个空格分隔。

第二行包含一个长度为 n 的字符串 s 。

第三行包含一个长度为 m 的字符串 t 。

输出格式

输出一行包含一个整数表示答案。

样例输入
3 6 5
abc
acbbac
样例输出
5
提示

【样例说明】

初始选择指针位于键盘 abc 上的 a ,输入 acbbac 这 6 个字符分别需要指针移动 0, 2, 1, 0, 1, 2 的距离,而最大移动距离为 5 ,所以最多输入 5 个字符,移动 0 + 2 + 1 + 0 + 1 = 4 的距离。

【评测用例规模与约定】

对于 20% 的评测用例,1 ≤ m ≤ 20;

对于所有评测用例,1 ≤ n ≤ 103 ,1 ≤ m ≤ 105 ,1 ≤ L ≤ 109 且 s, t 中只包含小写字母,且 s 中一定包含所有 t 中出现过的字母,数据保证随机。

思路

因为前缀和的最大长度满足,它之前所有字符都要满足条件【前面的字符匹配了,才能匹配后面的字符】考虑动态规划。希望找到的是实现这个前缀的最短路径长度。也就意味着它可以由到达它之前所在的相同字符的所有位置的最短路径长度和到达它同字符的所有位置的所有情况中,找到最短的那条路径,就是到达它的最短路径。

如果最短路径都无法满足<=最大允许长度,说明已经找到了最短路径。

结合下图理解
第一个字符不用考虑,因为它作为初始位置,默认从第二个字符开始看,也就是看它到它前一个字符的所有路径情况,找到实现它同字符所有位置最短的。

第一个b明显更靠近第一个1,到达它的最短路径也就是1。到达第二个b的最短路径明显是2。

在这里插入图片描述

依次类推,知道距离不够用或者找全了前缀为止。

#include<bits/stdc++.h> 
using namespace std;
vector<int> a[26];
const int N=1e3+10;
//到达该位置的最短路径长度。由n决定
int st[N]; 
 
int main()
{
    int n,m,l;
    cin>>n>>m>>l;
    string s,t;
    cin>>s>>t;
    //将到达这个字符的所有位置记录
    for(int i=0;i<n;i++)
    {
        a[s[i]-'a'].push_back(i);
    }
    
    //遍历目标前缀,从第2个字符开始
    for(int i=1;i<m;i++)
    {
        //找到当前字符,以及它之前的一个字符
        int cur = t[i]-'a';
        int pre = t[i-1]-'a';
        //如果相同代表不用移动
        if(cur==pre)continue;
        bool findn=false;
        int ans = 0x3f3f3f3f;
        //遍历每一个当前字符的位置,确认到达它的最短路径
        for(auto cur_c :a[cur])
        {
            for(auto pre_c:a[pre])
            {
                ans=min(ans,st[pre_c]+abs(pre_c-cur_c));
            }
            st[cur_c] = ans;
            //存在能够到达的路径
            if(ans<=l)
                findn = true;
        }
        //如果不能到达了就直接输出当前长度,默认是有一个的,因为可以指定初始位置
        if(!findn)
        {
            cout<<i<<"\n";
            return 0; 
        }
    }
    //都能到达输出目标前缀长度即可。
    cout<<m;
}
【评估多目标跟踪方法】9个高度敏捷目标在编队中的轨迹和测量研究(Matlab代码实现)内容概要:本文围绕“评估多目标跟踪方法”,重点研究9个高度敏捷目标在编队飞行中的轨迹生成与测量过程,并提供完整的Matlab代码实现。文中详细模拟了目标的动态行为、运动约束及编队结构,通过仿真获取目标的状态信息与观测数据,用于验证和比较不同多目标跟踪算法的性能。研究内容涵盖轨迹建模、噪声处理、传感器测量模拟以及数据可视化等关键技术环节,旨在为雷达、无人机编队、自动驾驶等领域的多目标跟踪系统提供可复现的测试基准。; 适合人群:具备一定Matlab编程基础,从事控制工程、自动化、航空航天、智能交通或人工智能等相关领域的研究生、科研人员及工程技术人员。; 使用场景及目标:①用于多目标跟踪算法(如卡尔曼滤波、粒子滤波、GM-CPHD等)的性能评估与对比实验;②作为无人机编队、空中交通监控等应用场景下的轨迹仿真与传感器数据分析的教学与研究平台;③支持对高度机动目标在复杂编队下的可观测性与跟踪精度进行深入分析。; 阅读建议:建议读者结合提供的Matlab代码进行实践操作,重点关注轨迹生成逻辑与测量模型构建部分,可通过修改目标数量、运动参数或噪声水平来拓展实验场景,进一步提升对多目标跟踪系统设计与评估的理解。
### 第十五蓝桥杯 B 题目解析 以下是针对第十五蓝桥杯 Python 和 C++ B 部分题目的一些解析: #### 特殊字符串 (Python B ) 此题的核心在于理解如何判断一个字符串是否满足特定条件。假设该题要求统计某种符合条件的子串数量,则可以通过枚举法实现。 ```python def count_special_strings(s): n = len(s) result = 0 for i in range(n): # 枚举起点 freq = {} distinct_count = 0 for j in range(i, n): # 枚举终点 char = s[j] if char not in freq: freq[char] = 1 distinct_count += 1 else: freq[char] += 1 if distinct_count == len(freq.keys()): # 判断当前窗口是否满足条件 result += 1 return result # 测试样例 s = "abc" print(count_special_strings(s)) # 输出应为63 [^1] ``` 上述代码通过双重循环遍历所有可能的子串,并利用字典记录字符频率来验证其特性。最终返回的结果应当匹配官方测试数据中的预期值 `63` 而不是误算成 `159`。 --- #### 小数精度问题 (C++ B ) 对于涉及浮点运算的问题,务必注意输出格式的要求。如果未按照指定的小数位数打印结果,可能会被判定为错误解答。例如,在某些情况下需要保留一位小数而非两位时,可以采用如下方式调整输出设置: ```cpp #include <iostream> #include <iomanip> // 提供setprecision功能 int main() { double value = 12.345; std::cout << std::fixed; // 设置固定小数点模式 std::cout << std::setprecision(1); // 控制显示的一位小数 std::cout << value << "\n"; // 正确输出: 12.3 } ``` 这里的关键是对标准库头文件 `<iomanip>` 的熟悉程度以及合理运用其中函数控制数值呈现形式[^2]。 --- #### 深度优先搜索 (DFS) 应用实例 当遇到复杂合或者路径探索类问题时,通常会考虑使用 DFS 方法求解最优方案之一。下面给出一个简单的框架用于处理此类场景下的递归调用逻辑: ```python visited = set() def dfs(current_state): global visited if current_state in visited: # 剪枝操作避免重复访问状态 return False if is_goal_reached(current_state): # 达到目标则停止继续深入 return True visited.add(current_state) # 记录已探查过的节点防止回环 for next_step in generate_next_steps(current_state): if dfs(next_step): # 如果找到可行路线立即退出 return True return False # 所有可能分支均失败后报告无果 # 初始化入口参数并启动算法流程 start_point = ... if dfs(start_point): print("Solution Found!") else: print("No Solution Exists.") ``` 以上伪代码展示了基本思路,实际应用需依据具体命题定制化修改各件定义如 `is_goal_reached()` 及 `generate_next_steps()` 等辅助方法。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值