蓝桥2022决赛B题解

蓝桥2022决赛B题解

T1 卡牌

题目描述

这天,小明在整理他的卡牌。

他一共有 n 种卡牌,第 i 种卡牌上印有正整数数 i(i ∈ [1, n]),且第 i 种卡牌 现有 ai 张。

而如果有 n 张卡牌,其中每种卡牌各一张,那么这 n 张卡牌可以被称为一 套牌。小明为了凑出尽可能多套牌,拿出了 m 张空白牌,他可以在上面写上数 i,将其当做第 i 种牌来凑出套牌。然而小明觉得手写的牌不太美观,决定第 i 种牌最多手写 bi 张。

请问小明最多能凑出多少套牌?

输入格式

输入共 3 行,第一行为两个正整数 n, m。

第二行为 n 个正整数 a1, a2, …, an。

第三行为 n 个正整数 b1, b2, …, bn。

输出格式

一行,一个整数表示答案。

数据范围

对于 30% 的数据,保证 n ≤ 2000 ;

对于 100% 的数据,保证 n ≤ 2 × 105 ; ai , bi ≤ 2n; m ≤ n2 。

思路

先以a的大小做一遍sort从小到大排序,想要直接找到答案的写法相对比较麻烦,可以直接二分答案做判定,判定一个答案的可行性比直接找到答案简单。

贴ACcode

#include
#include
#include
#define Maxn 200001
using namespace std;
long long n,m;
struct Card{
int a,b;
int operator < (const Card &x) const{
return a > x.a;
}
}card[Maxn];

int check(int x){
long long num = 0;
for(int i = 1;i <= n;i ++){
int def = x - card[i].a;
if(def > card[i].b) return 0;
else {
num += max(def,0);
if(num > m) return 0;
}
}
return 1;
}

int main(){
cin >> n >> m;
for(int i = 1;i <= n;i ++) cin >> card[i].a;
for(int i = 1;i <= n;i ++) cin >> card[i].b;
int l = 1,r = n;
while(r - l >= 0){
int mid = (l + r) >> 1;
if(check(mid)) l = mid + 1;
else r = mid - 1;
}
if(check®) cout << r;
else cout << l;
}

T2 最大数字

题目描述

给定一个正整数 N。你可以对 N 的任意一位数字执行任意次以下 2 种操作:

将该位数字加 1。如果该位数字已经是 9,加 1 之后变成 0。

将该位数字减 1。如果该位数字已经是 0,减 1 之后变成 9。

你现在总共可以执行 1 号操作不超过 A 次,2 号操作不超过 B 次。

请问你最大可以将 N 变成多少?

输入格式

第一行包含 3 个整数:N, A, B。

输出格式

一个整数代表答案。

数据范围

对于 30% 的数据,1 ≤ N ≤ 100; 0 ≤ A, B ≤ 10

对于 100% 的数据,1 ≤ N ≤ 10^17; 0 ≤ A, B ≤ 100

思路

先考虑对一位数字的操作,大位数字的影响绝对优先于小位,可以有一个贪心:优先使大位的数字达到9或尽可能使最高位更高,但是具体的操作顺序,不能直接判断出用操作1还是2更优,考虑Dfs,从大往小搜。

#include
#include
#include
using namespace std;
long long n,ans = 0;
int a,b,x[21],cnt = 0;
void Dfs(int now,int a,int b,int t){
if(x[now] == 9 && now <= cnt) Dfs(now + 1,a,b,x[now + 1]);
if(now > cnt) {
long long sum = 0;
for(int i = 1;i <= cnt;i ++){
sum *= 10;
sum += x[i];
}
ans = max(ans,sum);
return;
}
if(9 - t <= a) {
x[now] = 9;
Dfs(now + 1,a - (9 - t),b,x[now + 1]);
x[now] = t;
}
else{
x[now] = t + a;
Dfs(now + 1,0,b,x[now + 1]);
x[now] = t;
}
if(x[now] + 1 <= b) {
x[now] = 9;
Dfs(now + 1,a,b - (t + 1),x[now + 1]);
x[now] = t;
}
}
int main(){
cin >> n >> a >> b;
long long u = n;
while(n){cnt ++,n /= 10;}
for(int i = cnt;i >= 1;i --){
x[i] = u % 10;
u /= 10;
}
Dfs(1,a,b,x[1]);
cout << ans;
}

T3 出差

题目描述

A 国有 N 个城市,编号为 1 . . . N。小明是编号为 1 的城市中一家公司的员工,今天突然接到了上级通知需要去编号为 N 的城市出差。

由于疫情原因,很多直达的交通方式暂时关闭,小明无法乘坐飞机直接从城市 1 到达城市 N,需要通过其他城市进行陆路交通中转。小明通过交通信息网,查询到了 M 条城市之间仍然还开通的路线信息以及每一条路线需要花费的时间。

同样由于疫情原因,小明到达一个城市后需要隔离观察一段时间才能离开该城市前往其他城市。通过网络,小明也查询到了各个城市的隔离信息。(由于小明之前在城市 1,因此可以直接离开城市 1,不需要隔离)

由于上级要求,小明希望能够尽快赶到城市 N,因此他求助于你,希望你能帮他规划一条路线,能够在最短时间内到达城市 N。

输入格式

第 1 行:两个正整数 N, M, N 表示 A 国的城市数量,M 表示未关闭的路线数量

第 2 行:N 个正整数,第 i 个整数 Ci 表示到达编号为 i 的城市后需要隔离的时间

第 3 . . . M + 2 行:每行 3 个正整数,u, v, c,表示有一条城市 u 到城市 v 的双向路线仍然开通着,通过该路线的时间为 c

输出格式

第 1 行:1 个正整数,表示小明从城市 1 出发到达城市 N 的最短时间(到达城市 N,不需要计算城市 N 的隔离时间)

数据范围

对于 100% 的数据,1 ≤ N ≤ 1000 , 1 ≤ M ≤ 10000, 1 ≤ Ci ≤ 200, 1 ≤ u, v ≤ N, 1 ≤ c ≤ 1000

思路

最短路板子题,把隔离时间视为点权加到边权上即可。

贴ACcode:

#include
#include
#include
#include
#include
#include
using namespace std;
struct Edge{
int to,val;
}edge;
struct Node{
int index,dis;
bool operator < (const Node &x) const{
return dis > x.dis;
}
}node;
priority_queue q;
vector Point[10001];
long long dis[10001];
int c[10001],vis[10001];
void Dij(int start){
dis[start] = 0;
node.index = start;
node.dis = 0;
q.push(node);
while(!q.empty()){
node = q.top();
q.pop();
int u = node.index,d = node.dis;
// printf(“%d %d\n”,u,d);
if(vis[u]) continue;
vis[u] = 1;
for(int i = 0;i < Point[u].size();i ++){
int v = Point[u][i].to,w = Point[u][i].val;
if(dis[v] > dis[u] + w){
dis[v] = dis[u] + w;
if(!vis[v]){
node.index = v;
node.dis = dis[v];
q.push(node);
// printf(“%d %d\n”,v,dis[v]);
}
}
}
}
}
int main(){
int N,M;
cin >> N >> M;
for(int i = 1;i <= N;i ++) cin >> c[i];
for(int i = 1;i <= M;i ++){
int u,v,w;
cin >> u >> v >> w;
edge.to = v;
edge.val = w + c[v];
Point[u].push_back(edge);
edge.to = u;
edge.val = w + c[u];
Point[v].push_back(edge);
}
memset(dis,1000000001,sizeof(dis));
memset(vis,0,sizeof(vis));
Dij(1);
cout << dis[N] - c[N];
}

但是不知道为什么总是98。。。。不想调了

  • 19
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
树上选点是蓝桥杯Java题目中的一种类型,通常需要在给定的树结构中选择一个或多个节点作为目标节点,并进行相应的操作。下面是一个简单的树上选点蓝桥Java题解的示例: 题目描述: 给定一棵有N个节点的树,每个节点上都有一个非负整数值。现在需要选择一些节点,使得选择的节点的值之和最大,且所选节点不能相邻(即选了一个节点,则其父节点和子节点都不能选)。请编写一个程序,计算出最大的节点值之和。 解题思路: 这是一个典型的动态规划问题。我们可以定义一个数组dp,其中dp[i]表示以第i个节点为根节点的子树中所选节点的最大值之和。对于每个节点i,有两种情况: 1. 选择节点i:则其子节点都不能选,所以dp[i] = val[i] + dp[grandchild1] + dp[grandchild2] + ... 2. 不选择节点i:则其子节点可以选择或不选择,所以dp[i] = max(dp[child1], dp[child2], ...) 根据以上思路,我们可以使用递归或者迭代的方式来计算dp数组。最终,所求的最大值即为dp,其中1表示根节点。 代码示例: ```java public class TreeSelectPoint { public static void main(String[] args) { int[] values = {0, 1, 2, 3, 4, 5}; // 节点值数组,下标从1开始 int[][] edges = {{1, 2}, {1, 3}, {2, 4}, {2, 5}}; // 树的边关系数组 int n = values.length - 1; // 节点个数 int[] dp = new int[n + 1]; // 动态规划数组 // 构建树的邻接表 List<List<Integer>> adjacencyList = new ArrayList<>(); for (int i = 0; i <= n; i++) { adjacencyList.add(new ArrayList<>()); } for (int[] edge : edges) { int u = edge[0]; int v = edge[1]; adjacencyList.get(u).add(v); adjacencyList.get(v).add(u); } dfs(1, -1, values, adjacencyList, dp); // 从根节点开始进行深度优先搜索 System.out.println(dp[1]); // 输出最大节点值之和 } private static void dfs(int cur, int parent, int[] values, List<List<Integer>> adjacencyList, int[] dp) { dp[cur] = values[cur]; // 初始化当前节点的dp值为节点值 for (int child : adjacencyList.get(cur)) { if (child != parent) { // 避免重复访问父节点 dfs(child, cur, values, adjacencyList, dp); dp[cur] += dp[child]; // 更新当前节点的dp值 } } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值