蓝桥杯急救计划 day2 (1)

本文分析了四道来自蓝桥杯竞赛的编程题目,涉及动态规划求解包子凑数问题、树的砍伐模拟、环检测以及接龙数列问题,展示了算法设计和数据结构在解决实际问题中的应用。
摘要由CSDN通过智能技术生成

P8646 [蓝桥杯 2017 省 AB] 包子凑数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题意:有n种含不同数量包子的蒸笼,每种蒸笼的数量是无限的,问有多少种包子数是凑不出来的

思路:1.由裴蜀定理可知,只有当最大公约数为1时,才会有有限个凑不出来的数,也就是说只要gcd > 1, 就直接输出inf即可

2.剩下的考虑用dp来凑数

dp思路:如果某数i可以凑出,那么dp[i]就置为1,那么显然dp[i + a[j]]就都可以被凑出,每一轮全部标记为1就可以了

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

const int N = 110;

int a[N];

void solve()
{
	int n;
	cin >> n;
	
	for(int i = 1; i <= n; i ++ ) cin >> a[i];
	
	int g = 0; 
	for(int i = 1; i <= n; i ++ )
		g = __gcd(g, a[i]);
		
	if(g > 1)
	{
		cout << "INF" << endl;
		return;
	}
	
	bool dp[100100] = {0};
	dp[0] = 1;
	for(int i = 0; i <= 10000; i ++ ) //dp凑数
	{
		if(dp[i])
			for(int j = 1; j <= n; j ++ )
				dp[i + a[j]] = 1;	
	}
	
	int ans = 0;
	for(int i = 1; i <= 10000; i ++ )
		if(!dp[i]) ans ++;
		
	cout << ans << endl;
}
 
signed main()
{
	int t = 1;
	//cin >> t;
	while(t -- ) solve();
	return 0;
}

P8787 [蓝桥杯 2022 省 B] 砍竹子 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:1.通过观察(bushi,也可以先打个表看看最多几次就能砍成1)可以发现每棵树变成1的速度非常快,即每棵树其实不会被砍几次就变成1了,那我们就可以考虑这一堆树,以每棵树需要砍几次为依据对树进行分类(分层)。

2.然后直接枚举每一层去模拟即可(同一高度的树统一砍一次,降到下一层),具体看代码

#include<bits/stdc++.h>
#define int long long

using namespace std;
typedef pair<int, int> PII;

const int N = 2e6 + 10;
 
int h[N];
int f[N];
int cnt[N];

int getv(int x)
{
	return sqrtl(x / 2 + 1);
}

void solve()
{
	int n;
	cin >> n;
	
	for(int i = 1; i <= n; i ++ ) cin >> h[i];
	
	int maxx = 0;
	for(int i = 1; i <= n; i ++ )
	{
		int tmp = h[i];
		while(tmp > 1)
		{
			tmp = getv(tmp);
			cnt[i] ++;
		}
		maxx = max(maxx, cnt[i]);
	}
	
	int ans = 0;
	for(int i = maxx; i >= 1; i -- ) 
		for(int j = 1; j <= n; j ++ ) //每有一个跟前面的不相同的ans就++ 
			if(cnt[j] == i) //如果这颗树是当前层的话(第j棵树是第i层的话)
			{
				if(h[j] != h[j + 1]) ans ++;
				cnt[j] --, h[j] = getv(h[j]); //放在括号里面啊!! 
			}
	
	cout << ans << endl;
}

signed main()
{
	int t = 1;
	//cin >> t;
	while(t -- ) solve();
	return 0;
}

P8655 [蓝桥杯 2017 国 B] 发现环 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题意:这是一颗基环树,找出树上的环

思路:建双向图,用拓扑排序的思想从外部到内部消除边的影响,入度为1的点显然不会对环造成贡献,故只需将入度为1的点入队,去删除它所连的边即可;将拓扑后的度为1的值标记上,则剩下的未标记的点就是在环上的节点

#include<bits/stdc++.h>
#define int long long 

using namespace std;

const int N = 1e5 + 10;

int n;
vector<int> g[N];
int d[N];
bool st[N];

void topsort()
{
	//入度为1的点对环无贡献,故直接通过拓扑的思想删掉连边即可 
	queue<int> q;
	for(int i = 1; i <= n; i ++ )
		if(d[i] == 1)
		{
			 q.push(i);
			 st[i] = 1;
		}
	
	while(q.size())
	{
		int u = q.front();
		q.pop();
		
		for(int i = 0; i < g[u].size(); i ++ )
		{
			int nx = g[u][i];
			if(-- d[nx] == 1)
			{
				q.push(nx);
				st[nx] = 1;
			}
		}
	}
}

void solve()
{
	cin >> n;
	
	for(int i = 1; i <= n; i ++ )
	{
		int u, v;
		cin >> u >> v;
		g[u].push_back(v); //建立了无向图之后每个点的入度都至少为1 
		g[v].push_back(u);
		d[u] ++;
		d[v] ++;
	}
	
	topsort();
	for(int i = 1; i <= n; i ++ )
		if(!st[i]) cout << i << " ";
}

signed main()
{
	int t = 1;
	while(t -- ) solve();
	return 0;
}

4960. 子串简写 - AcWing题库

题意:就是找出长度大于等于K的,以c1为首,c2为尾的子串有多少个

思路:双指针,保证两个指针间距为K,算一个有关c1的前缀和或者是c2的后缀和,以c2的后缀和为例,从后往前统计c2的数量,若是碰到c1,则显然ans += sum(c2)

两个指针,i找c2,j找c1

#include<bits/stdc++.h>
#define int long long

using namespace std;

const int N = 3e5 + 10;

void solve()
{
	int k;
	string s;
	char a, b;
	
	cin >> k >> s >> a >> b;
	s = "$" + s;
	
	int cnt = 0;
	int ans = 0;
	//边找a边统计后缀,显然可以想到后缀和 
	//要有转换的思想在里面 
	for(int i = s.size() - 1, j = s.size() - k; i >= 1 && j >= 1; i --, j -- )
	{
		if(s[i] == b) cnt ++;
		if(s[j] == a) ans += cnt;
	}
	
	cout << ans << endl;
}

signed main()
{
	int t = 1;
	while(t -- )
	{
		solve();
	}
	return 0;
}

P9242 [蓝桥杯 2023 省 B] 接龙数列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:1.可以想到这个dp很像最长上升子序列,o(n ^ 2)可骗50分。用a[i]存该数的头部,b[i]存该数的尾部,则if(a[i] == b[j]) dp[i] = max(dp[i], dp[j] + 1);

2.考虑优化,在最长上升子序列dp转移的条件是 if (a[i] > a[j]),有一个大于的限制关系,而在本题中满足转移的条件是转移关系,可以考虑在顺次dp的过程中,开一个辅助数组,暂存以当前数为结尾的子序列的最长是多少,后面的直接接就可以了。

50分:

#include<bits/stdc++.h>
#define int long long

using namespace std;
typedef pair<int, int> PII;

const int N = 1e5 + 10;
 
int n;
int a[N], b[N];
int dp[N];

void solve()
{
	cin >> n;
	
	for(int i = 1; i <= n; i ++ )
	{
		string s;
		cin >> s;
		
		a[i] = s[0] - '0', b[i] = s[s.size() - 1] - '0';		
	}
	
	b[0] = INT_MAX;
	for(int i = 1; i <= n; i ++ )
	{
		dp[i] = 1;
		for(int j = 0; j <= i - 1; j ++ ) //可考虑优化掉一维
		{
			if(b[j] == a[i])
				dp[i] = max(dp[i], dp[j] + 1);
		}
	}
	
	cout << n - *max_element(dp + 1, dp + n + 1) << endl;
}

signed main()
{
	int T = 1;
	while(T -- ) solve();
	return 0;
}

100分:

#include<bits/stdc++.h>
#define int long long

using namespace std;
typedef pair<int, int> PII;

const int N = 1e5 + 10;
 
int n;
int a[N], b[N];
int dp[N], g[N];
//g数组存的是以数字i为结尾的接龙序列的最大长度 

void solve()
{
	cin >> n;
	
	for(int i = 1; i <= n; i ++ )
	{
		string s;
		cin >> s;
		
		a[i] = s[0] - '0', b[i] = s[s.size() - 1] - '0';		
	}
	
	b[0] = INT_MAX;
	for(int i = 1; i <= n; i ++ )
	{
		dp[i] = 1;
		dp[i] = g[a[i]] + 1; //g[a[i]]即当前子序列可以往上接的 
		g[b[i]] = max(g[b[i]], dp[i]); //更新以当前数的尾巴为结尾的子序列的最大长度 
	}
	
	cout << n - *max_element(dp + 1, dp + n + 1) << endl;
}

signed main()
{
	int T = 1;
	while(T -- ) solve();
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值