第十一届蓝桥杯B组省赛题(七月)

本博客包含 D、I、J 三道题的题解(E 不会),其中我感觉 D 和 E 是这次比赛最难的两道题…

D-题目描述:REPEAT程序

在这里插入图片描述
答案
241830

思路:
参考了 这篇博客 的思路

首先排除用python (毕竟这是C++的题解),观察片段可知:

① REPEAT 后面跟着的缩进的行,都是要乘以 REPEAT 后面的数字的
② 一行一行的读取(getline() / gets()
③ 我们只用记录每层循环乘以的数,和每层循环的缩进空格数,就知道当前 ans 处于第几层以及 ans 需要乘以的数
④ 当运行到某一行,先判断是否缩进空格数,以便我们知道当前是进入了下一层循环还是退出了上一层循环或是没变,再判断这是 REPEAT 语句(REPEAT 3:)还是加法语句(A = A + 3):如果这是 REPEAT 语句,变量 cheng 就要乘上后面的数,同时记录当前层数(pos)的 a [pos](每层循环乘以的数)与 b [pos](每层循环的缩进空格数);如果是加法语句,ans 就要 += 变量 cheng ∗ * 后面的数
⑤ 输出 ans

编程:

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

const int N=1e5+10;
int a[N],b[N];//cheng suojin

int main()
{
	string str;
	int pos=0;
	int cheng=1,ans=0;
	freopen("C:\\Users\\14805\\Desktop\\prog.txt","r",stdin);
	getline(cin,str);
	b[0]=-1;
	while(getline(cin,str))
	{
		int len=str.length();
		int p=0;
		while(str[p]==' ') p++;
		while(p<=b[pos]) cheng/=a[pos--];
		if(str[len-1]==':')//REPEAT
		{
			cheng*=(str[len-2]-'0');
			pos++;
			a[pos]=(str[len-2]-'0');b[pos]=p;
		}
		if(isdigit(str[len-1]))
		{
			ans+=(str[len-1]-'0')*cheng;
		}
	}
	cout<<ans;
	return 0;
}

E-题目描述:矩阵

在这里插入图片描述
思路:
参考了 这篇博客 的思路

但是抱歉!真的看不懂,找这种规律的题对我来说,不亚于用矩阵求斐波那契,这我在比赛的时候根本想不到哇!等我能看懂了再回来补充吧/(ㄒoㄒ)/~~


I-题目描述:整数拼接

在这里插入图片描述
思路:
参考了 这篇博客 的思路和 这篇题解 的代码

思路我觉得她讲的已经很好了,我就补充几点:
1、注意本题的长度,要用 long long
2、我用log10()+1函数代替表示数字长度,更多简化函数请看容易忽略的算法知识点
3、思路是先算放左边的数字,再与放右边的数匹配。之所以 ans+= 要写在 for 循环前面,是因为避免自己和自己拼接组合【手写实现样例的代码过程就很容易理解了】

编程:

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

const int K = 100010; //k的最大值 K 
int n,k;
ll s[K];
ll ans; //最终结果 
int dp[10][K]; //适应长度位数 与 拼在前面的数 

void work()
{
	for(int i=0;i<n;i++)
	{
		ans+=dp[(int)log10(s[i])+1][(k-s[i]%k)%k];
		int ten=10;
		for(int j=1;j<=9;j++)
		{
			dp[j][1ll*ten*s[i]%k]++;
			ten*=10;
		}
	}
}

int main()
{
	cin>>n>>k;
	for(int i=0;i<n;i++) cin>>s[i];
	work();
	memset(dp,0,sizeof(dp));
	reverse(s,s+n);
	work();
	cout<<ans;
	return 0;
}

/*
样例
4 2
1 2 3 4
*/

J-题目描述:网络分析

在这里插入图片描述
在这里插入图片描述
思路:
参考了 这篇题解 的思路和 这篇博客 的代码

在这里插入图片描述
主思路是并查集

当操作 1 时:把其中一个连通块的父节点并向另一个连通块的父节点(后者变为前者的父节点),前者的父节点的值要减去后者的父节点的值,因为最后输出每个节点的值的方法是:其本身的值加上其父节点的值【实在想不懂可以按样例画图理解】,但一开始每个节点的值都是0,其本身的值从哪里来的呢?其实就是只有一个节点的连通块实施了操作 2,导致其本身加上了值

当操作 2 时:将操作的节点所在的连通块的父节点加上值(而不是连通块的每一个节点都加上值)这样做的目的是为了减少时间损耗,不然每次遍历一遍太慢了;在搜索父节点的函数中我们加入了压缩路径,它的作用是使所有父节点都只含一层子节点(理解为:find(子节点) == father[子节点])能加快搜索效率

注意:一开始每个节点的父节点即是其本身

编程:

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

const int N=100010;
int s[N],father[N];

int find(int x)
{
	int a=x;
	while(father[x]!=x) x=father[x];
	//压缩路径
	while(a!=father[a])
	{
		father[a]=x;
		a=father[a];
	}
	return x;
}

void merge(int x, int y)
{
	x = find(x), y = find(y);
	if(x != y)
	{
		father[x] = y;
		s[x] -= s[y];
	}
}


int main() 
{
    int n,m,t,x1,x2;
    cin>>n>>m;
    for(int i=1;i<=n;i++) father[i]=i;
    for(int i=1;i<=m;i++)
    {
    	cin>>t>>x1>>x2;
    	if(t==1)
    	{
    		merge(x1,x2);
		}
		else
		{
    		s[find(x1)]+=x2;
		}
	}
	for(int i=1;i<=n;i++)
	{
		int ans=s[i];
		if(i!=father[i]) ans+=s[find(i)];
		cout<<ans;
		if(i!=n) cout<<' ';
		else cout<<endl;
	}
    return 0;
}

/*
样例
4 8
1 1 2
2 1 10
2 3 5
1 4 1
2 2 2
1 1 2
1 2 4
2 2 1
*/

遇到的 bug:

void merge(int x, int y)
{
	x = find(x), y = find(y);
	if(x != y)
	{
		father[x] = y;
		s[x] -= s[y];
	}
}

上面是没有问题的 merge函数 源代码

void merge(int x,int y)
{
	if(find(x)!=find(y))
	{
		father[find(x)]=find(y);
		s[find(x)]-=s[find(y)];
	}
}

但如果我 merge函数 写成这样的会报错,原因未知,放着记录一下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值