23年蓝桥杯省赛C++B组

23年蓝桥省赛

A.日期统计

赛时好像没写出来?还是咋写的来着我忘了,反正这个解法挺妙的,枚举每一天的日期,因为题目限制了2023的日期且每种日期只计算一次

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
const int N = 110;
int d[N];
int ans;
void solve(){
	for(int i = 1 ; i <= 100 ; i ++) cin >> d[i];
	int days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
	int target[10] = {0,2,0,2,3};
	for(int month = 1 ; month <= 12 ; month ++){
		for(int day = 1 ; day <= days[month] ; day ++){
			target[5] = month / 10, target[6] = month%10;
			target[7] = day / 10 , target[8] = day % 10;
			int k = 1;
			for(int i = 1 ; i <= 100 ; i ++){
				if(d[i] == target[k]) k ++;
				if(k == 9) {
					ans ++;
					break;
				}
			}	
		}
	}
	cout << ans;
}	
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int _ = 1;
	//cin >> _;
	//while(_--) solve();
	cout << 235;
	return 0;
}

B.01串的熵

读懂题目就行了。赛时和补题的时候都出现了把 1 e 3 1e3 1e3当成 1 e − 3 1e-3 1e3的情况,和没看见 0 0 0的个数多这个条件。

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
double n = 23333333;
double ans = 11625907.5798;
int x;
void solve(){
	// for(int i = 1; i <= n / 2; i ++)
	// {
	// 	x = (double) i;
	// 	double now = - x * x / n * log2(x/n) - (n-x)*(n-x)/n*log2((n-x)/n);
	// 	if(abs(now - ans) <= 1e-3) cout << i ;
	// }
	cout << 11027421;
}	
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int _ = 1;
	//cin >> _;
	while(_--) solve();
	return 0;
}	

C.冶炼金属

赛时好像做出来了,发现了结论。但不知道为什么补题的时候就没反应,但这题好像想考的是二分。
B ≤ A V < B + 1 = > A B + 1 < V ≤ A B B\leq\frac{A}{V}< B+1=>\frac{A}{B+1}<V\leq\frac{A}{B} BVA<B+1=>B+1A<VBA

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
int mn = 0, mx =  0x3f3f3f3f;
void solve(){
	int a, b;cin >> a >> b;
	mx = min(mx,a/b);
	mn = max(mn,a/(b+1)+1);
}	
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int _ = 1;
	cin >> _;
	while(_--) solve();
	cout << mn << " " << mx;
	return 0;
}

D.飞机降落

赛时就在想怎么贪心,不知道按什么排序,一直都在想,根本没想过爆搜,结果补题第一反应也是贪心,真服了自己了,还是做题做少了,明明寒假牛客别人叫“这题主要考察了贪心”都不会上当,这就上当了。

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
struct plan{
	int t,d,l;
};
vector<plan> v(20);
bool vis[20];
int n,f;
void dfs(int time,int k){
	if(k == n){
		f = 1;
		return ;
	}
	for(int i = 1 ; i <= n ; i ++){
		if(time > v[i].t + v[i].d || vis[i]) continue;
		vis[i] = 1;
		dfs(max(time,v[i].t) + v[i].l , k + 1);
		vis[i] = 0;
	}
}
void solve(){
	memset(vis,0,sizeof vis);
	f = 0;
	cin >> n;
	for(int i = 1; i <= n ; i ++) cin >> v[i].t >> v[i].d >> v[i].l;
	dfs(0,0);
	cout << (f?"YES\n":"NO\n");
}	
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int _ = 1;
	cin >> _;
	while(_--) solve();
	return 0;
}

E.接龙数列

题意:给定一个长度为 n n n的数组,请问最少删除多少个数组,能使得剩下的数字都能像 12 , 24 , 46 , 67 12,24,46,67 12,24,46,67这样接龙下去

思路:典型的 d p dp dp d p [ i ] dp[i] dp[i]表示当前以数字 i ( 0 ≤ i ≤ 9 ) i(0\leq i\leq9) i(0i9)为结尾的接龙数组的最大长度

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
const int N = 1e5 + 10;
int dp[10];
int n;
void solve(){
	cin >> n;
	for(int i = 1 ; i <= n ; i ++) {
		string s; cin >> s;
		int start = s[0] - '0', end = s[s.size()-1] - '0';
		dp[end] = max(dp[end],dp[start]+1);
	}
	int ans = 0;
	for(int i = 0 ; i <= 9 ; i ++)
		ans = max(dp[i],ans);
	cout << n - ans;
}	
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int _ = 1;
	//cin >> _;
	while(_--) solve();
	return 0;
}

F.岛屿个数

题意:给定一个大小为 n × m n\times m n×m,由 0 , 1 0,1 0,1组成的图, 0 0 0表示海水, 1 1 1表示陆地,请问有多少个岛屿,当一个岛屿被另一个岛屿圈住时,此岛屿不计数

思路:此题最难的是怎么判断一个岛屿是否被其他岛屿圈住,如果这个岛屿的边界点能够通过走海水,走到地图边界则没有被包围,且此时能够走的方向变成 8 8 8个,如下图中,岛屿没有被包住

11111
10001
10101
10001
11110
#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
#define fi first
#define se second
const int N = 55;
string g[N];
bool vis[N][N], used[N][N];
int n, m, ans;
int dx[]={0,0,-1,1,1,1,-1,-1};
int dy[]={1,-1,0,0,1,-1,1,-1};
void bfs(int x,int y){
	queue<pair<int,int>> q;
	q.push({x,y}); vis[x][y] = 1;
	while(q.size()){
	 	x = q.front().fi, y = q.front().se; q.pop();
	 	for(int i = 0 ; i < 4 ; i ++)
	 	{
	 		int nx = x + dx[i] , ny = y + dy[i];
	 		if(nx < 0 || nx >= n || ny < 0 || ny >= m || vis[nx][ny] || g[nx][ny] == '0') continue;
	 		vis[nx][ny] = 1;
	 		q.push({nx,ny});
	 	}
	}
}
bool bfs_out(int x,int y){
	memset(used,0,sizeof used);
	queue<pair<int,int>> q;
	q.push({x,y}); used[x][y] = 1;
	while(q.size()){
	 	x = q.front().fi, y = q.front().se; q.pop();
	 	if(x == 0 || x == n - 1 || y == 0 || y == m - 1) return true;
	 	for(int i = 0 ; i < 8 ; i ++)
	 	{
	 		int nx = x + dx[i] , ny = y + dy[i];
	 		if(nx < 0 || nx >= n || ny < 0 || ny >= m || used[nx][ny] || g[nx][ny] == '1') continue;
	 		used[nx][ny] = 1;
	 		q.push({nx,ny});
	 	}
	}
	return false;
}
void solve(){
	memset(vis,0,sizeof vis);
	ans = 0;
	cin >> n >> m;
	for(int i = 0 ; i < n ; i ++)
		cin >> g[i];
	for(int i = 0 ; i < n ; i ++)
		for(int j = 0 ; j < m ; j ++)
		{
			if(!vis[i][j] && g[i][j] == '1')
			{
				bfs(i,j);
				if(bfs_out(i,j)) ans ++;
			}
		}
	cout << ans << endl;
}	
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int _ = 1;
	cin >> _;
	while(_--) solve();
	return 0;
}

G.子串简写

前缀和计数

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
const int N = 5e5 + 10;
int sum[N];
string s;
char a,b;
int n;
void solve(){
	cin >> n >> s >> a >> b;
	s = " " + s;	
	for(int i = 1 ; i < s.size() ; i ++)
		sum[i] =  sum[i-1] + (s[i] == a);
	int ans = 0;
	for(int i = n ; i < s.size() ; i ++)
		if(s[i] == b)ans += sum[i-n+1];
	cout << ans;
}	
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int _ = 1;
	//cin >> _;
	while(_--) solve();
	return 0;
}

H.整数删除

题意:给定一个长度为n的数组,进行k次操作,每次操作为删除数组中最小的元素,将其值加到左右两元素上,输出最后的数组

思路:用优先队列和链表优化,单调队列查询当前数组中的最小元素何其下标,用链表来查找上一个节点和下一个节点并删除元素

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
#define val first
#define id second
int n,k;
const int N = 5e5 + 10;
int a[N],pre[N],ne[N];
typedef pair<int,int> PII;
priority_queue<PII> q;
void solve(){
	cin >> n >> k;
	for(int i = 1; i <= n ; i ++)
	{
		cin >> a[i];
		q.push({-a[i],-i});
		pre[i] = i - 1;
		ne[i] = i + 1;
	}
	pre[1] = -1,ne[n] = -1;
	while(k --){
		int val,id;
		do{	
			auto t = q.top(); q.pop();
			val = -t.val, id = -t.id;
		}while(a[id] != val && q.size());
		int pe = pre[id], nt = ne[id];
		if(pe != -1){
			a[pe] += val;
			ne[pe] = nt;
			q.push({-a[pe],-pe});
		}
		if(nt != -1){
			a[nt] += val;
			pre[nt] = pe;
			q.push({-a[nt],-nt});
		}
		a[id] = -1;
	}
	for(int i = 1 ; i <= n ; i ++)
		if(a[i]!=-1) cout << a[i] << " ";

}	
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int _ = 1;
	//cin >> _;
	while(_--) solve();
	return 0;
}

I.景区导游

题意:给定一棵由 n n n个点组成的树,对于给定的长度为 k k k的节点遍历顺序,问删除 k i k_i ki后,按顺序遍历剩下节点的路径长度

思路:对于树上一点和根节点的距离跑一遍 d f s dfs dfs就能确定,而对于书上两点 u , v u,v u,v的距离 p a t h ( u , v ) = d [ u ] + d [ v ] − 2 × d [ l c a ( u , v ) ] path(u,v) = d[u]+d[v]-2\times d[lca(u,v)] path(u,v)=d[u]+d[v]2×d[lca(u,v)],所以最后删除 k i k_i ki后,记路径总长度为 s s s,则路径长度应该为 s k i ′ = s − p a t h ( k i − 1 , k i ) − p a t h ( k i , k i + 1 ) + p a t h ( k i − 1 , k i + 1 ) s'_{k_i}=s-path(k_{i-1},k_i)-path(k_{i},k_{i+1})+path(k_{i-1},k_{i+1}) ski=spath(ki1,ki)path(ki,ki+1)+path(ki1,ki+1)

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
const int N = 1e5 + 10;
int n, k;
struct edge{int v,w;};
vector<edge> e[N];
int fa[N][21],dep[N],d[N];
int a[N],sum;
void dfs(int u,int f){
	dep[u] = dep[f] + 1;
	fa[u][0] = f;
	for(int i = 1; i <= 20 ; i ++)
		fa[u][i] = fa[fa[u][i-1]][i-1];
	for(auto t : e[u]){
		int v = t.v, w = t.w;
		if(v != f){
			d[v] = d[u] + w;
			dfs(v,u);
		}
	}
}
int lca(int u,int v){
	if(dep[u] < dep[v]) swap(u,v);
	for(int i = 20 ; i >= 0 ; i --)
		if(dep[fa[u][i]] >= dep[v])
		 u = fa[u][i];
	if(u == v) return u;
	for(int i = 20 ; i >= 0 ; i --)
		if(fa[u][i] != fa[v][i])
			u = fa[u][i] , v = fa[v][i];
	return fa[u][0];
}
int path(int u,int v){
	if(!u || !v) return 0;
	return d[u] + d[v] - 2 * d[lca(u,v)];
}
void solve(){
	cin >> n >> k;
	for(int i = 1; i < n ; i ++)
	{
		int u,v,w;cin >> u >> v >> w;
		e[u].push_back({v,w});
		e[v].push_back({u,w});
	}
	dfs(1,0);
	for(int i = 1; i <= k ; i ++) {
		cin >> a[i];
		sum += path(a[i-1],a[i]);
	}
	for(int i = 1 ; i <= k ; i ++)
		cout << sum - path(a[i-1],a[i]) - path(a[i],a[i+1]) + path(a[i-1],a[i+1]) << " ";
}	
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int _ = 1;
	//cin >> _;
	while(_--) solve();
	return 0;
}

J.砍树

知识点:树上差分,lca,题意和思路之后再补吧
题意:对于给定 n n n个点的一棵树,对于给定 m m m对点,问是否存在一条边,当删除此边后,这 m m m对点都无法互相到达

思路:对于每一对点 u , v u,v u,v,到达 l c a ( u , v ) lca(u,v) lca(u,v)的下面的边的计数都 + 1 +1 +1,上面的点都不动,进行树上差分即可实现,即 s [ u ] + + , s [ v ] + + , s [ l c a ( u , v ) ] − = 2 s[u]++,s[v]++,s[lca(u,v)]-=2 s[u]++,s[v]++,s[lca(u,v)]=2,最后对树跑一边 d f s dfs dfs求前缀和

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
#define int long long
const int N = 1e5 + 10;
vector<int> e[N],num[N];
int fa[N][21], dep[N];
int n, m;
int s[N],ans;
void dfs(int u,int f){
	dep[u] = dep[f] + 1;	
	fa[u][0] = f;
	for(int i = 1; i <= 20 ; i ++)
		fa[u][i] = fa[fa[u][i-1]][i-1];
	for(auto v : e[u])
		if(v != f) dfs(v,u);
}
int lca(int u,int v){
	if(dep[u] < dep[v]) swap(u,v);
	for(int i = 20 ; i >= 0 ; i --)
		if(dep[fa[u][i]] >= dep[v])
			u = fa[u][i];
	if(u == v) return u;
	for(int i = 20 ; i >= 0 ; i --)
		if(fa[u][i] != fa[v][i])
			u = fa[u][i], v = fa[v][i];
	return fa[u][0];
}
void dfss(int u,int f){
	for(int i = 0 ; i < e[u].size() ; i ++){
		int v = e[u][i], p = num[u][i];
		if(v == f) continue;
		dfss(v,u);
		s[u] += s[v];
		//cout << v << " " << s[v] << endl;
		if(s[v] == m) ans = max(ans,p);	
	}
}

void solve(){
	cin >> n >> m;
	for(int i = 1; i < n ; i ++)
	{
		int a, b; cin >> a >> b;
		e[a].push_back(b);
		e[b].push_back(a);
		num[a].push_back(i);
		num[b].push_back(i);
	}
	dfs(1,0);
	for(int i = 1; i <= m ; i ++)
	{
		int a, b; cin >> a >> b;
		s[a] += 1, s[b] += 1, s[lca(a,b)] -= 2;
	}
	dfss(1,0);
	//for(int i = 1; i <= n ; i ++) cout << i << " " <<s[i] << endl;
	cout << (ans?ans:-1);
}	
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int _ = 1;
	//cin >> _;
	while(_--) solve();
	return 0;
}

感想

重新做了去年省赛题目,发现去年真的是连火门都没摸到,太菜了,虽然现在也是个巨菜,加训啊!!!留个愿望在这儿,先不写出来,怕到时候丢人

  • 61
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值